Reading libraries and parameters

library(tidyverse)
library(quickpsy)
library(cowplot)
list.files("R", full.names = TRUE) %>% walk(source)
source("graphical_parameters.R")
source("parameters.R")
load(file = "logdata/dat_asym.RData")

Fixed lapse rate to 0% or 1%

fun_normal<- function(x, p) {
  pnorm(x, p[1] - p[2], p[3]) - pnorm(x, p[1] + p[2], p[3])
}
fun_normal_asyn_one <- function(x, p) {
  .01 + (1- .01) * pnorm(x, p[1] - p[2], p[3]) - (1- .01) * pnorm(x, p[1] + p[2], p[3])
}
fit_asym_without_asyn_zero <- quickpsy(dat_asym, 
                     orientation, response, 
                     fun = fun_normal,
                     parini = list(pini_origin_asym, pini_origin_asym, pini_scale),
                     grouping = .(subject, reference),
                     bootstrap = "none")
fit_asym_without_asyn_one <- quickpsy(dat_asym, 
                             orientation, response, 
                             fun = fun_normal_asyn_one,
                             parini = list(pini_origin_asym, pini_origin_asym, pini_scale),
                             grouping = .(subject, reference),
                             bootstrap = "none")
ms_asym_without_asyn_zero_vs_without_asyn_one <- model_selection_aic(
  fit_asym_without_asyn_zero$aic, fit_asym_without_asyn_one$aic) %>% 
  mutate(best = if_else(best == "first", 
                        "without_asyn_zero", "without_asyn_one"))
ms_asym_without_asyn_zero_vs_without_asyn_one %>% 
  group_by(best) %>% 
  count() 
ggplot() + facet_grid(subject ~ reference) +
  geom_point(data = fit_asym_without_asyn_zero$averages, 
             aes(x = orientation, y = prob)) +
  geom_line(data = fit_asym_without_asyn_zero$curves, 
            aes(x = x, y = y, color = "without asyn zero")) +
  geom_line(data = fit_asym_without_asyn_one$curves, 
            aes(x = x, y = y, color = "without asyn one")) +
  geom_text(data = ms_asym_without_asyn_zero_vs_without_asyn_one,
            aes(x = .7, y = .1, label = best), size = 3) +
  theme_grey() + theme(legend.position = "top") 

Adding a fixed lapse rate does not change much the fits.

Checking that the parameters do not reach the boundaries of the initial parameters

fit_asym_without_asyn_zero$par %>% 
  filter(parn == "p1") %>% 
  filter(abs(par) >= pini_origin_asym[2])
fit_asym_without_asyn_zero$par %>% 
  filter(parn == "p2") %>% 
  filter(abs(par) >= pini_origin_asym[2])
fit_asym_without_asyn_zero$par %>% 
  filter(parn == "p3") %>% 
  filter(abs(par) >= pini_scale[2])

One variable lapse rate vs fixed lapse rate

fun_normal_with_one_asyn <- function(x, p) {
  p[4] + (1 - p[4]) * pnorm(x, p[1] - p[2], p[3]) - (1 - p[4]) * pnorm(x, p[1] + p[2], p[3])
}
fit_asym_with_one_asyn <- quickpsy(dat_asym, 
          orientation, response, 
          fun = fun_normal_with_one_asyn,
          parini = list(pini_origin_asym, pini_origin_asym, pini_scale, pini_lapse),
          grouping = .(subject, reference),
          bootstrap = "none")
fit_asym_without_asyn_zero_better <- ms_asym_without_asyn_zero_vs_without_asyn_one %>% 
  filter(best == "without_asyn_zero") %>% 
  select(subject, reference)
fit_asym_without_asyn_one_better <- ms_asym_without_asyn_zero_vs_without_asyn_one %>% 
  filter(best == "without_asyn_one") %>% 
  select(subject, reference)
                                   
fit_asym_without_asyn_zero_better_logliks <- fit_asym_without_asyn_zero$logliks %>%
  semi_join(fit_asym_without_asyn_zero_better, by = c("subject", "reference"))
  
fit_asym_without_asyn_one_better_logliks <- fit_asym_without_asyn_one$logliks %>%
  semi_join(fit_asym_without_asyn_one_better, by = c("subject", "reference"))
fit_asym_without_asyn_logliks <- fit_asym_without_asyn_zero_better_logliks %>% 
  bind_rows(fit_asym_without_asyn_one_better_logliks)
  
ms_asym_with_one_asyn_vs_without_asyn <- model_selection_lrt(
  fit_asym_with_one_asyn$logliks, fit_asym_without_asyn_logliks)  %>% 
  mutate(best = if_else(best == "first", 
                        "with_one_asyn", "without_asyn"))
fit_asym_with_one_asyn_better <- ms_asym_with_one_asyn_vs_without_asyn %>% 
  filter(best == "with_one_asyn") %>% 
  select(subject, reference)
fit_asym_without_asyn_zero_better_curves <- fit_asym_without_asyn_zero$curves %>%
  semi_join(fit_asym_without_asyn_zero_better, by = c("subject", "reference"))
  
fit_asym_without_asyn_one_better_curves <- fit_asym_without_asyn_one$curves %>%
  semi_join(fit_asym_without_asyn_one_better, by = c("subject", "reference"))
fit_asym_without_asyn_curves <- fit_asym_without_asyn_zero_better_curves %>% 
  bind_rows(fit_asym_without_asyn_one_better_curves)
ggplot() + facet_grid(subject ~ reference) +
  geom_point(data = fit_asym_with_one_asyn$averages, 
             aes(x = orientation, y = prob)) +
  geom_line(data = fit_asym_with_one_asyn$curves, 
            aes(x = x, y = y, color = "one asyn")) +
  geom_line(data = fit_asym_without_asyn_curves, 
            aes(x = x, y = y, color = "without asyn")) +
  geom_text(data = ms_asym_with_one_asyn_vs_without_asyn, 
            aes(x = .7, y = .1, label = best), size = 3) +
  theme_grey() + theme(legend.position = "top") 

Adding a lapse rate parameter produce poor fits.

Fitting

refs <- dat_asym %>% distinct(vertical, references, reference)
fit_asym_full_fun <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, p[1] - p[2], p[3]) - pnorm(x, p[1] + p[2], p[3])
  fun_2 <- function(x, p) pnorm(x, p[1] - p[4], p[6]) - pnorm(x, p[1] + p[5], p[6])
  
  pini <- list(pini_origin_asym, pini_origin_asym, pini_scale, 
               pini_origin_asym, pini_origin_asym, pini_scale)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_full_same_slope_fun <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, p[1] - p[2], p[3]) - pnorm(x, p[1] + p[2], p[3])
  fun_2 <- function(x, p) pnorm(x, p[1] - p[4], p[3]) - pnorm(x, p[1] + p[5], p[3])
  
  pini <- list(pini_origin_asym, pini_origin_asym, pini_scale, 
               pini_origin_asym, pini_origin_asym)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_full_sym_crit_fun <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, p[1] - p[2], p[3]) - pnorm(x, p[1] + p[2], p[3])
  fun_2 <- function(x, p) pnorm(x, p[1] - p[4], p[5]) - pnorm(x, p[1] + p[4], p[5])
  
  pini <- list(pini_origin_asym, pini_origin_asym, pini_scale, 
               pini_origin_asym, pini_scale)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_full_sym_crit_same_fun <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, p[1] - p[2], p[3]) - pnorm(x, p[1] + p[2], p[3])
  fun_2 <- function(x, p) pnorm(x, p[1] - p[2], p[4]) - pnorm(x, p[1] + p[2], p[4])
  
  pini <- list(pini_origin_asym, pini_origin_asym, pini_scale, 
               pini_scale)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_full_sym_crit_same_zero_fun <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, - p[1], p[2]) - pnorm(x, p[1], p[2])
  fun_2 <- function(x, p) pnorm(x, - p[1], p[3]) - pnorm(x, p[1], p[3])
  
  pini <- list(pini_origin_asym, pini_scale, pini_scale)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_full_same_slope_sym_crit_fun <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, p[1] - p[2], p[3]) - pnorm(x, p[1] + p[2], p[3])
  fun_2 <- function(x, p) pnorm(x, p[1] - p[4], p[3]) - pnorm(x, p[1] + p[4], p[3])
  
  pini <- list(pini_origin_asym, pini_origin_asym, pini_scale, 
               pini_origin_asym)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_full_same_slope_sym_crit_zero_fun <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, - p[1], p[2]) - pnorm(x,p[1], p[2])
  fun_2 <- function(x, p) pnorm(x, - p[3], p[2]) - pnorm(x, p[3], p[2])
  
  pini <- list(pini_origin_asym, pini_scale, 
               pini_origin_asym)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_full_same_slope_sym_crit_same_fun <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, p[1] - p[2], p[3]) - pnorm(x, p[1] + p[2], p[3])
  fun_2 <- function(x, p) pnorm(x, p[1] - p[2], p[3]) - pnorm(x, p[1] + p[2], p[3])
  
  pini <- list(pini_origin_asym, pini_origin_asym, pini_scale)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_full_same_slope_sym_crit_same_zero_fun <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, - p[1], p[2]) - pnorm(x, p[1], p[2])
  fun_2 <- function(x, p) pnorm(x, - p[1], p[2]) - pnorm(x, p[1], p[2])
  
  pini <- list(pini_origin_asym, pini_scale)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_full_fun_zero <- function(data) {
  
  fun_1 <- function(x, p) pnorm(x, - p[1], p[2]) - pnorm(x, p[1], p[2])
  fun_2 <- function(x, p) pnorm(x, - p[3], p[4]) - pnorm(x, p[3], p[4])
  
  pini <- list(pini_origin_asym, pini_scale, 
               pini_origin_asym, pini_scale)
  fun_df <- data %>% 
    distinct(references) %>% 
    arrange(references) %>% 
    bind_cols(tibble(fun = c(fun_1, fun_2))) 
  quickpsy(data, orientation, response, fun = fun_df, xmin = -4, xmax = 4,
           parini = pini, bootstrap = "none", grouping = .(references),
           threshold = FALSE)
}
fit_asym_best <- dat_asym %>% 
  group_by(subject, vertical) %>% 
  nest() %>% 
  mutate(fit_asym_full = map(data, fit_asym_full_fun),
         fit_asym_full_sym_crit = map(data, fit_asym_full_sym_crit_fun),
         fit_asym_full_sym_crit_same = map(data, fit_asym_full_sym_crit_same_fun),
         fit_asym_full_sym_crit_same_zero = map(data, fit_asym_full_sym_crit_same_zero_fun),
         fit_asym_full_zero = map(data, fit_asym_full_fun_zero),
         fit_asym_full_same_slope = map(data, fit_asym_full_same_slope_fun),
         fit_asym_full_same_slope_sym_crit = map(data, fit_asym_full_same_slope_sym_crit_fun),
         fit_asym_full_same_slope_sym_crit_zero = map(data, fit_asym_full_same_slope_sym_crit_zero_fun),
         fit_asym_full_same_slope_sym_crit_same = map(data, fit_asym_full_same_slope_sym_crit_same_fun),
         fit_asym_full_same_slope_sym_crit_same_zero = map(data, fit_asym_full_same_slope_sym_crit_same_zero_fun)) %>% 
      #   fit_asym_zero = map(data, fit_asym_zero_fun),
       #  fit_asym_p = map(data, fit_asym_p_fun),
       #  fit_asym_d = map(data, fit_asym_d_fun)) %>% 
  select(-data)

Full

ggplot() + facet_wrap(subject ~ vertical, ncol = 6) +
  geom_point(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full, "averages")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full, "curves")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
            aes(x = x, y = y, color = references)) +
  theme_grey() + theme(legend.position = "top") 

Full same slope

ggplot() + facet_wrap(subject ~ vertical, ncol = 6) +
  geom_point(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope, "averages")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope, "curves")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
            aes(x = x, y = y, color = references)) +
  theme_grey() + theme(legend.position = "top") 

Full vs full same slope

asym_full_vs_full_same_slope <- fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(fit_asym_full_loglik = map(fit_asym_full, "logliks"),
         fit_asym_full_same_slope_loglik = map(fit_asym_full_same_slope, "logliks"),
         best = map2_chr(fit_asym_full_loglik, fit_asym_full_same_slope_loglik, 
                    ~model_selection_lrt(.x, .y)$best))
asym_full_vs_full_same_slope %>% 
  group_by(best) %>% 
  count()     
         
best_asym_full_no_same_slope <- asym_full_vs_full_same_slope %>% 
  filter(best == "first") %>% 
  select(subject, vertical)
best_asym_full_same_slope <- asym_full_vs_full_same_slope %>% 
  filter(best == "second") %>% 
  select(subject, vertical)

Full no same slope sym crit

ggplot() + facet_wrap(subject ~ vertical, ncol = 6) +
  geom_point(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_sym_crit, "averages")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_sym_crit, "curves")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
            aes(x = x, y = y, color = references)) +
  theme_grey() + theme(legend.position = "top") 

Full no same slope vs full no same slope sym crit

asym_full_no_same_slope_vs_full_no_same_slope_sym_crit <- fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(fit_asym_full_loglik = map(fit_asym_full, "logliks"),
         fit_asym_full_sym_crit_loglik = map(fit_asym_full_sym_crit, "logliks"),
         best = map2_chr(fit_asym_full_loglik, fit_asym_full_sym_crit_loglik, 
                    ~model_selection_lrt(.x, .y)$best))
asym_full_no_same_slope_vs_full_no_same_slope_sym_crit %>% 
  semi_join(best_asym_full_no_same_slope) %>% 
  group_by(best) %>% 
  count()     
Joining, by = c("subject", "vertical")
         
best_asym_full_no_same_slope_sym_crit <- asym_full_no_same_slope_vs_full_no_same_slope_sym_crit %>% 
  semi_join(best_asym_full_no_same_slope) %>% 
  filter(best == "second") %>% 
  select(subject, vertical)
Joining, by = c("subject", "vertical")

Full no same slope sym crit same

ggplot() + facet_wrap(subject ~ vertical, ncol = 6) +
  geom_point(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_sym_crit_same, "averages")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_sym_crit_same, "curves")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
            aes(x = x, y = y, color = references)) +
  theme_grey() + theme(legend.position = "top") 

Full no same slope sym crit vs full no same slope sym crit same

asym_full_no_same_slope_sym_crit_vs_full_no_same_slope_sym_crit_same <- fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(fit_asym_full_sym_crit_loglik = map(fit_asym_full_sym_crit, "logliks"),
         fit_asym_full_sym_crit_same_loglik = map(fit_asym_full_sym_crit_same, "logliks"),
         best = map2_chr(fit_asym_full_sym_crit_loglik, fit_asym_full_sym_crit_same_loglik, 
                    ~model_selection_lrt(.x, .y)$best))
asym_full_no_same_slope_sym_crit_vs_full_no_same_slope_sym_crit_same %>% 
  semi_join(best_asym_full_no_same_slope_sym_crit) %>% 
  group_by(best) %>% 
  count()     
Joining, by = c("subject", "vertical")
         
best_asym_full_no_same_slope_sym_crit_same <- asym_full_no_same_slope_sym_crit_vs_full_no_same_slope_sym_crit_same %>% 
  semi_join(best_asym_full_no_same_slope_sym_crit) %>% 
  filter(best == "second") %>% 
  select(subject, vertical)
Joining, by = c("subject", "vertical")

Full no same slope sym crit same zero

ggplot() + facet_wrap(subject ~ vertical, ncol = 6) +
  geom_point(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_sym_crit_same_zero, "averages")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_sym_crit_same_zero, "curves")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
            aes(x = x, y = y, color = references)) +
  theme_grey() + theme(legend.position = "top") 

Full no same slope sym crit same vs full no same slope sym crit same zero

asym_full_no_same_slope_sym_crit_same_vs_full_no_same_slope_sym_crit_same_zero <- fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(fit_asym_full_sym_crit_same_loglik = map(fit_asym_full_sym_crit_same, "logliks"),
         fit_asym_full_sym_crit_same_zero_loglik = map(fit_asym_full_sym_crit_same_zero, "logliks"),
         best = map2_chr(fit_asym_full_sym_crit_same_loglik, fit_asym_full_sym_crit_same_zero_loglik, 
                    ~model_selection_lrt(.x, .y)$best))
asym_full_no_same_slope_sym_crit_same_vs_full_no_same_slope_sym_crit_same_zero %>% 
  semi_join(best_asym_full_no_same_slope_sym_crit_same) %>% 
  group_by(best) %>% 
  count()     
Joining, by = c("subject", "vertical")
         
### Add to s vs d
best_asym_full_no_same_slope_sym_crit_same_no_zero <- asym_full_no_same_slope_sym_crit_same_vs_full_no_same_slope_sym_crit_same_zero %>%
  semi_join(best_asym_full_no_same_slope_sym_crit_same) %>% 
  filter(best == "first") %>% 
  select(subject, vertical) %>% 
  mutate(best = "response")
Joining, by = c("subject", "vertical")

Full same slope sym crit

ggplot() + facet_wrap(subject ~ vertical, ncol = 6) +
  geom_point(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope_sym_crit, "averages")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope_sym_crit, "curves")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
            aes(x = x, y = y, color = references)) +
  theme_grey() + theme(legend.position = "top") 

Full same slope vs full same slope sym crit

asym_full_same_slope_vs_full_same_slope_sym_crit <- fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(fit_asym_full_same_slope_loglik = map(fit_asym_full_same_slope, "logliks"),
         fit_asym_full_same_slope_sym_crit_loglik = map(fit_asym_full_same_slope_sym_crit, "logliks"),
         best = map2_chr(fit_asym_full_same_slope_loglik, fit_asym_full_same_slope_sym_crit_loglik, 
                    ~model_selection_lrt(.x, .y)$best))
asym_full_same_slope_vs_full_same_slope_sym_crit %>% 
  semi_join(best_asym_full_same_slope) %>% 
  group_by(best) %>% 
  count()     
Joining, by = c("subject", "vertical")
         
### Add to s vs d
best_asym_full_same_slope_no_sym_crit <- asym_full_same_slope_vs_full_same_slope_sym_crit %>%
  semi_join(best_asym_full_same_slope) %>% 
  filter(best == "first") %>% 
  select(subject, vertical) %>% 
  mutate(best = "no sym crit")
Joining, by = c("subject", "vertical")
best_asym_full_same_slope_sym_crit <- asym_full_same_slope_vs_full_same_slope_sym_crit %>%
  semi_join(best_asym_full_same_slope) %>% 
  filter(best == "second") %>% 
  select(subject, vertical) 
Joining, by = c("subject", "vertical")

Full same slope sym crit same

ggplot() + facet_wrap(subject ~ vertical, ncol = 6) +
  geom_point(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope_sym_crit_same, "averages")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope_sym_crit_same, "curves")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
            aes(x = x, y = y, color = references)) +
  theme_grey() + theme(legend.position = "top") 

Full same slope sym crit vs full same slope sym crit same

asym_full_same_slope_sym_crit_vs_full_same_slope_sym_crit_same <- fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(fit_asym_full_same_slope_sym_crit_loglik = map(fit_asym_full_same_slope_sym_crit, "logliks"),
         fit_asym_full_same_slope_sym_crit_same_loglik = map(fit_asym_full_same_slope_sym_crit_same, "logliks"),
         best = map2_chr(fit_asym_full_same_slope_sym_crit_loglik, fit_asym_full_same_slope_sym_crit_same_loglik, 
                    ~model_selection_lrt(.x, .y)$best))
asym_full_same_slope_sym_crit_vs_full_same_slope_sym_crit_same %>% 
  semi_join(best_asym_full_same_slope_sym_crit) %>% 
  group_by(best) %>% 
  count()     
Joining, by = c("subject", "vertical")
         
best_asym_full_same_slope_sym_crit_no_same <- asym_full_same_slope_sym_crit_vs_full_same_slope_sym_crit_same %>%
  semi_join(best_asym_full_same_slope_sym_crit) %>% 
  filter(best == "first") %>% 
  select(subject, vertical) 
Joining, by = c("subject", "vertical")
best_asym_full_same_slope_sym_crit_same <- asym_full_same_slope_sym_crit_vs_full_same_slope_sym_crit_same %>%
  semi_join(best_asym_full_same_slope_sym_crit) %>% 
  filter(best == "second") %>% 
  select(subject, vertical) 
Joining, by = c("subject", "vertical")

Full same slope sym crit no same zero

ggplot() + facet_wrap(subject ~ vertical, ncol = 6) +
  geom_point(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope_sym_crit_zero, "averages")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope_sym_crit_zero, "curves")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
            aes(x = x, y = y, color = references)) +
  theme_grey() + theme(legend.position = "top") 

Full same slope sym crit no same vs full same slope sym crit no same zero

asym_full_same_slope_sym_crit_no_same_vs_full_same_slope_sym_crit_no_same_zero <- fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(fit_asym_full_same_slope_sym_crit_loglik = map(fit_asym_full_same_slope_sym_crit, "logliks"),
         fit_asym_full_same_slope_sym_crit_zero_loglik = map(fit_asym_full_same_slope_sym_crit_zero, "logliks"),
         best = map2_chr(fit_asym_full_same_slope_sym_crit_loglik, fit_asym_full_same_slope_sym_crit_zero_loglik, 
                    ~model_selection_lrt(.x, .y)$best))
asym_full_same_slope_sym_crit_no_same_vs_full_same_slope_sym_crit_no_same_zero %>% 
  semi_join(best_asym_full_same_slope_sym_crit_no_same) %>% 
  group_by(best) %>% 
  count()     
Joining, by = c("subject", "vertical")
         
### Add to s vs d
best_asym_full_same_slope_sym_crit_no_same_no_zero <- asym_full_same_slope_sym_crit_no_same_vs_full_same_slope_sym_crit_no_same_zero %>%
  semi_join(best_asym_full_same_slope_sym_crit_no_same) %>% 
  filter(best == "first") %>% 
  select(subject, vertical) %>% 
  mutate(best = "response")
Joining, by = c("subject", "vertical")

Full same slope sym crit same zero

ggplot() + facet_wrap(subject ~ vertical, ncol = 6) +
  geom_point(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope_sym_crit_same_zero, "averages")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = fit_asym_best %>% 
               mutate(temp = map(fit_asym_full_same_slope_sym_crit_same_zero, "curves")) %>% 
               select(subject, vertical, temp) %>% 
               unnest(temp), 
            aes(x = x, y = y, color = references)) +
  theme_grey() + theme(legend.position = "top") 

Full same slope sym crit same vs full same slope sym crit same zero

asym_full_same_slope_sym_crit_same_vs_full_same_slope_sym_crit_same_zero <- fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(fit_asym_full_same_slope_sym_crit_same_loglik = map(fit_asym_full_same_slope_sym_crit_same, "logliks"),
         fit_asym_full_same_slope_sym_crit_same_zero_loglik = map(fit_asym_full_same_slope_sym_crit_same_zero, "logliks"),
         best = map2_chr(fit_asym_full_same_slope_sym_crit_same_loglik, fit_asym_full_same_slope_sym_crit_same_zero_loglik, 
                    ~model_selection_lrt(.x, .y)$best))
asym_full_same_slope_sym_crit_same_vs_full_same_slope_sym_crit_same_zero %>% 
  semi_join(best_asym_full_same_slope_sym_crit_same) %>% 
  group_by(best) %>% 
  count()     
Joining, by = c("subject", "vertical")
         
### Add to s vs d
best_asym_full_same_slope_sym_crit_same_no_zero <- asym_full_same_slope_sym_crit_same_vs_full_same_slope_sym_crit_same_zero %>%
  semi_join(best_asym_full_same_slope_sym_crit_same) %>% 
  filter(best == "first") %>% 
  select(subject, vertical) %>% 
  mutate(best = "sensory")
Joining, by = c("subject", "vertical")
### Add to s vs d
best_asym_full_same_slope_sym_crit_same_zero <- asym_full_same_slope_sym_crit_same_vs_full_same_slope_sym_crit_same_zero %>%
  semi_join(best_asym_full_same_slope_sym_crit_same) %>% 
  filter(best == "second") %>% 
  select(subject, vertical) %>% 
  mutate(best = "zero")
Joining, by = c("subject", "vertical")

Averages, curves and parameters

fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_sym_crit_same, "averages")) %>% 
  unnest(temp)
  
  
asym_averages_s_vs_d <- 
  (fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full, "averages")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_no_same_slope_sym_crit_same_no_zero)) %>% 
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "averages")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_no_sym_crit))) %>% 
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "averages")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_sym_crit_no_same_no_zero))) %>%   
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "averages")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_sym_crit_same_no_zero))) %>% 
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "averages")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_sym_crit_same_zero))) 
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
asym_curves_s_vs_d <- 
  (fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full, "curves")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_no_same_slope_sym_crit_same_no_zero)) %>% 
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "curves")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_no_sym_crit))) %>% 
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "curves")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_sym_crit_no_same_no_zero))) %>%   
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "curves")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_sym_crit_same_no_zero))) %>% 
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "curves")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_sym_crit_same_zero))) 
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
asym_par_s_vs_d <- 
  (fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full, "par")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_no_same_slope_sym_crit_same_no_zero)) %>% 
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "par")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_no_sym_crit))) %>% 
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "par")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_sym_crit_no_same_no_zero))) %>%   
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "par")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_sym_crit_same_no_zero))) %>% 
  bind_rows((fit_asym_best %>% 
  group_by(subject, vertical) %>% 
  transmute(temp = map(fit_asym_full_same_slope, "par")) %>% 
  unnest(temp) %>% semi_join(best_asym_full_same_slope_sym_crit_same_zero))) 
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
Joining, by = c("subject", "vertical")
  
asym_par_s_vs_d_long <- asym_par_s_vs_d %>% 
  spread(parn,par) %>% 
  mutate(pfirst = p1, 
         psecond = p1 + .5 * (p5 - p4),
         psensory = .5 * (pfirst + psecond),
         pdecisional = pfirst - psensory)
ggplot() + facet_wrap(subject ~ vertical, ncol = 4) +
  geom_point(data = asym_averages_s_vs_d, 
             aes(x = orientation, y = prob, color = references)) +
  geom_line(data = asym_curves_s_vs_d, 
            aes(x = x, y = y, color = references)) +
  # geom_vline(data = asym_par_s_vs_d_long,
  #            aes(xintercept = pfirst, lty = "pfirst")) +
  # geom_vline(data = asym_par_s_vs_d_long,
  #            aes(xintercept = psecond, lty = "psecond")) +
    geom_vline(data = asym_par_s_vs_d_long,
             aes(xintercept = psensory, lty = "psensory")) +
    geom_vline(data = asym_par_s_vs_d_long,
             aes(xintercept = psensory + pdecisional, lty = "psensory  + pdecisional")) +
  theme_grey() + theme(legend.position = "top") 

NA

Add all best

best_asym <- best_asym_full_no_same_slope_sym_crit_same_no_zero %>% 
  bind_rows(best_asym_full_same_slope_no_sym_crit) %>% 
  bind_rows(best_asym_full_same_slope_sym_crit_no_same_no_zero) %>% 
  bind_rows(best_asym_full_same_slope_sym_crit_same_no_zero) %>%  
  bind_rows(best_asym_full_same_slope_sym_crit_same_zero) 
refs <- dat_asym %>% distinct(vertical, references, reference)
asym_averages_s_vs_d_best <-  asym_averages_s_vs_d %>%
  left_join(best_asym) %>% 
  left_join(refs)
Joining, by = c("subject", "vertical")
Joining, by = c("vertical", "references")
  
asym_curves_s_vs_d_best <- asym_curves_s_vs_d %>% 
  left_join(best_asym) %>% 
  left_join(refs)
Joining, by = c("subject", "vertical")
Joining, by = c("vertical", "references")
asym_par_s_vs_d_best <- asym_par_s_vs_d %>% 
  left_join(best_asym) 
Joining, by = c("subject", "vertical")
asym_par_s_vs_d_best_long <- asym_par_s_vs_d_long %>% 
  left_join(best_asym) 
Joining, by = c("subject", "vertical")
asym_par_s_vs_d_best_abs <- asym_par_s_vs_d_best_long %>% 
  select(subject, vertical, psensory, pdecisional, best) %>% 
  gather(parn, par, - subject, - vertical, -best) %>% 
  mutate(parn = if_else(parn == "psensory", 
                             "Sensory\nbias", "Decisional\nbias"),
                abs_par = abs(par))

Save data

save(asym_averages_s_vs_d_best, file = "logdata/asym_averages_s_vs_d_best.RData")
save(asym_curves_s_vs_d_best, file = "logdata/asym_curves_s_vs_d_best.RData")
save(asym_par_s_vs_d_best, file = "logdata/asym_par_s_vs_d_best.RData")
save(asym_par_s_vs_d_best_long, file = "logdata/asym_par_s_vs_d_best_long.RData")
save(asym_par_s_vs_d_best_abs, file = "logdata/asym_par_s_vs_d_best_abs.RData")
LS0tCnRpdGxlOiAiU3ltbWV0cmljIHRhc2sgIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyMgUmVhZGluZyBsaWJyYXJpZXMgYW5kIHBhcmFtZXRlcnMKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShxdWlja3BzeSkKbGlicmFyeShjb3dwbG90KQoKbGlzdC5maWxlcygiUiIsIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUgd2Fsayhzb3VyY2UpCnNvdXJjZSgiZ3JhcGhpY2FsX3BhcmFtZXRlcnMuUiIpCnNvdXJjZSgicGFyYW1ldGVycy5SIikKCmxvYWQoZmlsZSA9ICJsb2dkYXRhL2RhdF9hc3ltLlJEYXRhIikKYGBgCgoKIyMjIEZpeGVkIGxhcHNlIHJhdGUgdG8gMCUgb3IgMSUKCmBgYHtyIGZpZy5oZWlnaHQ9MjUsIGZpZy53aWR0aD04fQoKZnVuX25vcm1hbDwtIGZ1bmN0aW9uKHgsIHApIHsKICBwbm9ybSh4LCBwWzFdIC0gcFsyXSwgcFszXSkgLSBwbm9ybSh4LCBwWzFdICsgcFsyXSwgcFszXSkKfQoKZnVuX25vcm1hbF9hc3luX29uZSA8LSBmdW5jdGlvbih4LCBwKSB7CiAgLjAxICsgKDEtIC4wMSkgKiBwbm9ybSh4LCBwWzFdIC0gcFsyXSwgcFszXSkgLSAoMS0gLjAxKSAqIHBub3JtKHgsIHBbMV0gKyBwWzJdLCBwWzNdKQp9CgpmaXRfYXN5bV93aXRob3V0X2FzeW5femVybyA8LSBxdWlja3BzeShkYXRfYXN5bSwgCiAgICAgICAgICAgICAgICAgICAgIG9yaWVudGF0aW9uLCByZXNwb25zZSwgCiAgICAgICAgICAgICAgICAgICAgIGZ1biA9IGZ1bl9ub3JtYWwsCiAgICAgICAgICAgICAgICAgICAgIHBhcmluaSA9IGxpc3QocGluaV9vcmlnaW5fYXN5bSwgcGluaV9vcmlnaW5fYXN5bSwgcGluaV9zY2FsZSksCiAgICAgICAgICAgICAgICAgICAgIGdyb3VwaW5nID0gLihzdWJqZWN0LCByZWZlcmVuY2UpLAogICAgICAgICAgICAgICAgICAgICBib290c3RyYXAgPSAibm9uZSIpCgpmaXRfYXN5bV93aXRob3V0X2FzeW5fb25lIDwtIHF1aWNrcHN5KGRhdF9hc3ltLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmllbnRhdGlvbiwgcmVzcG9uc2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1biA9IGZ1bl9ub3JtYWxfYXN5bl9vbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyaW5pID0gbGlzdChwaW5pX29yaWdpbl9hc3ltLCBwaW5pX29yaWdpbl9hc3ltLCBwaW5pX3NjYWxlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cGluZyA9IC4oc3ViamVjdCwgcmVmZXJlbmNlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib290c3RyYXAgPSAibm9uZSIpCgptc19hc3ltX3dpdGhvdXRfYXN5bl96ZXJvX3ZzX3dpdGhvdXRfYXN5bl9vbmUgPC0gbW9kZWxfc2VsZWN0aW9uX2FpYygKICBmaXRfYXN5bV93aXRob3V0X2FzeW5femVybyRhaWMsIGZpdF9hc3ltX3dpdGhvdXRfYXN5bl9vbmUkYWljKSAlPiUgCiAgbXV0YXRlKGJlc3QgPSBpZl9lbHNlKGJlc3QgPT0gImZpcnN0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJ3aXRob3V0X2FzeW5femVybyIsICJ3aXRob3V0X2FzeW5fb25lIikpCgptc19hc3ltX3dpdGhvdXRfYXN5bl96ZXJvX3ZzX3dpdGhvdXRfYXN5bl9vbmUgJT4lIAogIGdyb3VwX2J5KGJlc3QpICU+JSAKICBjb3VudCgpIAoKZ2dwbG90KCkgKyBmYWNldF9ncmlkKHN1YmplY3QgfiByZWZlcmVuY2UpICsKICBnZW9tX3BvaW50KGRhdGEgPSBmaXRfYXN5bV93aXRob3V0X2FzeW5femVybyRhdmVyYWdlcywgCiAgICAgICAgICAgICBhZXMoeCA9IG9yaWVudGF0aW9uLCB5ID0gcHJvYikpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpdF9hc3ltX3dpdGhvdXRfYXN5bl96ZXJvJGN1cnZlcywgCiAgICAgICAgICAgIGFlcyh4ID0geCwgeSA9IHksIGNvbG9yID0gIndpdGhvdXQgYXN5biB6ZXJvIikpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpdF9hc3ltX3dpdGhvdXRfYXN5bl9vbmUkY3VydmVzLCAKICAgICAgICAgICAgYWVzKHggPSB4LCB5ID0geSwgY29sb3IgPSAid2l0aG91dCBhc3luIG9uZSIpKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBtc19hc3ltX3dpdGhvdXRfYXN5bl96ZXJvX3ZzX3dpdGhvdXRfYXN5bl9vbmUsCiAgICAgICAgICAgIGFlcyh4ID0gLjcsIHkgPSAuMSwgbGFiZWwgPSBiZXN0KSwgc2l6ZSA9IDMpICsKICB0aGVtZV9ncmV5KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgCmBgYAoKCkFkZGluZyBhIGZpeGVkIGxhcHNlIHJhdGUgZG9lcyBub3QgY2hhbmdlIG11Y2ggdGhlIGZpdHMuIAoKCiMjIyBDaGVja2luZyB0aGF0IHRoZSBwYXJhbWV0ZXJzIGRvIG5vdCByZWFjaCB0aGUgYm91bmRhcmllcyBvZiB0aGUgaW5pdGlhbCBwYXJhbWV0ZXJzCgpgYGB7cn0KZml0X2FzeW1fd2l0aG91dF9hc3luX3plcm8kcGFyICU+JSAKICBmaWx0ZXIocGFybiA9PSAicDEiKSAlPiUgCiAgZmlsdGVyKGFicyhwYXIpID49IHBpbmlfb3JpZ2luX2FzeW1bMl0pCgpmaXRfYXN5bV93aXRob3V0X2FzeW5femVybyRwYXIgJT4lIAogIGZpbHRlcihwYXJuID09ICJwMiIpICU+JSAKICBmaWx0ZXIoYWJzKHBhcikgPj0gcGluaV9vcmlnaW5fYXN5bVsyXSkKCmZpdF9hc3ltX3dpdGhvdXRfYXN5bl96ZXJvJHBhciAlPiUgCiAgZmlsdGVyKHBhcm4gPT0gInAzIikgJT4lIAogIGZpbHRlcihhYnMocGFyKSA+PSBwaW5pX3NjYWxlWzJdKQpgYGAKCgojIyMgT25lIHZhcmlhYmxlIGxhcHNlIHJhdGUgdnMgZml4ZWQgbGFwc2UgcmF0ZQoKYGBge3IgZmlnLmhlaWdodD0yMCwgZmlnLndpZHRoPTh9CmZ1bl9ub3JtYWxfd2l0aF9vbmVfYXN5biA8LSBmdW5jdGlvbih4LCBwKSB7CiAgcFs0XSArICgxIC0gcFs0XSkgKiBwbm9ybSh4LCBwWzFdIC0gcFsyXSwgcFszXSkgLSAoMSAtIHBbNF0pICogcG5vcm0oeCwgcFsxXSArIHBbMl0sIHBbM10pCn0KCmZpdF9hc3ltX3dpdGhfb25lX2FzeW4gPC0gcXVpY2twc3koZGF0X2FzeW0sIAogICAgICAgICAgb3JpZW50YXRpb24sIHJlc3BvbnNlLCAKICAgICAgICAgIGZ1biA9IGZ1bl9ub3JtYWxfd2l0aF9vbmVfYXN5biwKICAgICAgICAgIHBhcmluaSA9IGxpc3QocGluaV9vcmlnaW5fYXN5bSwgcGluaV9vcmlnaW5fYXN5bSwgcGluaV9zY2FsZSwgcGluaV9sYXBzZSksCiAgICAgICAgICBncm91cGluZyA9IC4oc3ViamVjdCwgcmVmZXJlbmNlKSwKICAgICAgICAgIGJvb3RzdHJhcCA9ICJub25lIikKCgpmaXRfYXN5bV93aXRob3V0X2FzeW5femVyb19iZXR0ZXIgPC0gbXNfYXN5bV93aXRob3V0X2FzeW5femVyb192c193aXRob3V0X2FzeW5fb25lICU+JSAKICBmaWx0ZXIoYmVzdCA9PSAid2l0aG91dF9hc3luX3plcm8iKSAlPiUgCiAgc2VsZWN0KHN1YmplY3QsIHJlZmVyZW5jZSkKCmZpdF9hc3ltX3dpdGhvdXRfYXN5bl9vbmVfYmV0dGVyIDwtIG1zX2FzeW1fd2l0aG91dF9hc3luX3plcm9fdnNfd2l0aG91dF9hc3luX29uZSAlPiUgCiAgZmlsdGVyKGJlc3QgPT0gIndpdGhvdXRfYXN5bl9vbmUiKSAlPiUgCiAgc2VsZWN0KHN1YmplY3QsIHJlZmVyZW5jZSkKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmZpdF9hc3ltX3dpdGhvdXRfYXN5bl96ZXJvX2JldHRlcl9sb2dsaWtzIDwtIGZpdF9hc3ltX3dpdGhvdXRfYXN5bl96ZXJvJGxvZ2xpa3MgJT4lCiAgc2VtaV9qb2luKGZpdF9hc3ltX3dpdGhvdXRfYXN5bl96ZXJvX2JldHRlciwgYnkgPSBjKCJzdWJqZWN0IiwgInJlZmVyZW5jZSIpKQogIApmaXRfYXN5bV93aXRob3V0X2FzeW5fb25lX2JldHRlcl9sb2dsaWtzIDwtIGZpdF9hc3ltX3dpdGhvdXRfYXN5bl9vbmUkbG9nbGlrcyAlPiUKICBzZW1pX2pvaW4oZml0X2FzeW1fd2l0aG91dF9hc3luX29uZV9iZXR0ZXIsIGJ5ID0gYygic3ViamVjdCIsICJyZWZlcmVuY2UiKSkKCmZpdF9hc3ltX3dpdGhvdXRfYXN5bl9sb2dsaWtzIDwtIGZpdF9hc3ltX3dpdGhvdXRfYXN5bl96ZXJvX2JldHRlcl9sb2dsaWtzICU+JSAKICBiaW5kX3Jvd3MoZml0X2FzeW1fd2l0aG91dF9hc3luX29uZV9iZXR0ZXJfbG9nbGlrcykKICAKbXNfYXN5bV93aXRoX29uZV9hc3luX3ZzX3dpdGhvdXRfYXN5biA8LSBtb2RlbF9zZWxlY3Rpb25fbHJ0KAogIGZpdF9hc3ltX3dpdGhfb25lX2FzeW4kbG9nbGlrcywgZml0X2FzeW1fd2l0aG91dF9hc3luX2xvZ2xpa3MpICAlPiUgCiAgbXV0YXRlKGJlc3QgPSBpZl9lbHNlKGJlc3QgPT0gImZpcnN0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJ3aXRoX29uZV9hc3luIiwgIndpdGhvdXRfYXN5biIpKQoKZml0X2FzeW1fd2l0aF9vbmVfYXN5bl9iZXR0ZXIgPC0gbXNfYXN5bV93aXRoX29uZV9hc3luX3ZzX3dpdGhvdXRfYXN5biAlPiUgCiAgZmlsdGVyKGJlc3QgPT0gIndpdGhfb25lX2FzeW4iKSAlPiUgCiAgc2VsZWN0KHN1YmplY3QsIHJlZmVyZW5jZSkKCmZpdF9hc3ltX3dpdGhvdXRfYXN5bl96ZXJvX2JldHRlcl9jdXJ2ZXMgPC0gZml0X2FzeW1fd2l0aG91dF9hc3luX3plcm8kY3VydmVzICU+JQogIHNlbWlfam9pbihmaXRfYXN5bV93aXRob3V0X2FzeW5femVyb19iZXR0ZXIsIGJ5ID0gYygic3ViamVjdCIsICJyZWZlcmVuY2UiKSkKICAKZml0X2FzeW1fd2l0aG91dF9hc3luX29uZV9iZXR0ZXJfY3VydmVzIDwtIGZpdF9hc3ltX3dpdGhvdXRfYXN5bl9vbmUkY3VydmVzICU+JQogIHNlbWlfam9pbihmaXRfYXN5bV93aXRob3V0X2FzeW5fb25lX2JldHRlciwgYnkgPSBjKCJzdWJqZWN0IiwgInJlZmVyZW5jZSIpKQoKZml0X2FzeW1fd2l0aG91dF9hc3luX2N1cnZlcyA8LSBmaXRfYXN5bV93aXRob3V0X2FzeW5femVyb19iZXR0ZXJfY3VydmVzICU+JSAKICBiaW5kX3Jvd3MoZml0X2FzeW1fd2l0aG91dF9hc3luX29uZV9iZXR0ZXJfY3VydmVzKQoKZ2dwbG90KCkgKyBmYWNldF9ncmlkKHN1YmplY3QgfiByZWZlcmVuY2UpICsKICBnZW9tX3BvaW50KGRhdGEgPSBmaXRfYXN5bV93aXRoX29uZV9hc3luJGF2ZXJhZ2VzLCAKICAgICAgICAgICAgIGFlcyh4ID0gb3JpZW50YXRpb24sIHkgPSBwcm9iKSkgKwogIGdlb21fbGluZShkYXRhID0gZml0X2FzeW1fd2l0aF9vbmVfYXN5biRjdXJ2ZXMsIAogICAgICAgICAgICBhZXMoeCA9IHgsIHkgPSB5LCBjb2xvciA9ICJvbmUgYXN5biIpKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBmaXRfYXN5bV93aXRob3V0X2FzeW5fY3VydmVzLCAKICAgICAgICAgICAgYWVzKHggPSB4LCB5ID0geSwgY29sb3IgPSAid2l0aG91dCBhc3luIikpICsKICBnZW9tX3RleHQoZGF0YSA9IG1zX2FzeW1fd2l0aF9vbmVfYXN5bl92c193aXRob3V0X2FzeW4sIAogICAgICAgICAgICBhZXMoeCA9IC43LCB5ID0gLjEsIGxhYmVsID0gYmVzdCksIHNpemUgPSAzKSArCiAgdGhlbWVfZ3JleSgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpIApgYGAKCkFkZGluZyBhIGxhcHNlIHJhdGUgcGFyYW1ldGVyIHByb2R1Y2UgcG9vciBmaXRzLiAKCgojIyMgRml0dGluZwpgYGB7ciBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD0xM30KcmVmcyA8LSBkYXRfYXN5bSAlPiUgZGlzdGluY3QodmVydGljYWwsIHJlZmVyZW5jZXMsIHJlZmVyZW5jZSkKCmZpdF9hc3ltX2Z1bGxfZnVuIDwtIGZ1bmN0aW9uKGRhdGEpIHsKICAKICBmdW5fMSA8LSBmdW5jdGlvbih4LCBwKSBwbm9ybSh4LCBwWzFdIC0gcFsyXSwgcFszXSkgLSBwbm9ybSh4LCBwWzFdICsgcFsyXSwgcFszXSkKICBmdW5fMiA8LSBmdW5jdGlvbih4LCBwKSBwbm9ybSh4LCBwWzFdIC0gcFs0XSwgcFs2XSkgLSBwbm9ybSh4LCBwWzFdICsgcFs1XSwgcFs2XSkKICAKICBwaW5pIDwtIGxpc3QocGluaV9vcmlnaW5fYXN5bSwgcGluaV9vcmlnaW5fYXN5bSwgcGluaV9zY2FsZSwgCiAgICAgICAgICAgICAgIHBpbmlfb3JpZ2luX2FzeW0sIHBpbmlfb3JpZ2luX2FzeW0sIHBpbmlfc2NhbGUpCgogIGZ1bl9kZiA8LSBkYXRhICU+JSAKICAgIGRpc3RpbmN0KHJlZmVyZW5jZXMpICU+JSAKICAgIGFycmFuZ2UocmVmZXJlbmNlcykgJT4lIAogICAgYmluZF9jb2xzKHRpYmJsZShmdW4gPSBjKGZ1bl8xLCBmdW5fMikpKSAKCiAgcXVpY2twc3koZGF0YSwgb3JpZW50YXRpb24sIHJlc3BvbnNlLCBmdW4gPSBmdW5fZGYsIHhtaW4gPSAtNCwgeG1heCA9IDQsCiAgICAgICAgICAgcGFyaW5pID0gcGluaSwgYm9vdHN0cmFwID0gIm5vbmUiLCBncm91cGluZyA9IC4ocmVmZXJlbmNlcyksCiAgICAgICAgICAgdGhyZXNob2xkID0gRkFMU0UpCn0KCmZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9mdW4gPC0gZnVuY3Rpb24oZGF0YSkgewogIAogIGZ1bl8xIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIHBbMV0gLSBwWzJdLCBwWzNdKSAtIHBub3JtKHgsIHBbMV0gKyBwWzJdLCBwWzNdKQogIGZ1bl8yIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIHBbMV0gLSBwWzRdLCBwWzNdKSAtIHBub3JtKHgsIHBbMV0gKyBwWzVdLCBwWzNdKQogIAogIHBpbmkgPC0gbGlzdChwaW5pX29yaWdpbl9hc3ltLCBwaW5pX29yaWdpbl9hc3ltLCBwaW5pX3NjYWxlLCAKICAgICAgICAgICAgICAgcGluaV9vcmlnaW5fYXN5bSwgcGluaV9vcmlnaW5fYXN5bSkKCiAgZnVuX2RmIDwtIGRhdGEgJT4lIAogICAgZGlzdGluY3QocmVmZXJlbmNlcykgJT4lIAogICAgYXJyYW5nZShyZWZlcmVuY2VzKSAlPiUgCiAgICBiaW5kX2NvbHModGliYmxlKGZ1biA9IGMoZnVuXzEsIGZ1bl8yKSkpIAoKICBxdWlja3BzeShkYXRhLCBvcmllbnRhdGlvbiwgcmVzcG9uc2UsIGZ1biA9IGZ1bl9kZiwgeG1pbiA9IC00LCB4bWF4ID0gNCwKICAgICAgICAgICBwYXJpbmkgPSBwaW5pLCBib290c3RyYXAgPSAibm9uZSIsIGdyb3VwaW5nID0gLihyZWZlcmVuY2VzKSwKICAgICAgICAgICB0aHJlc2hvbGQgPSBGQUxTRSkKfQoKZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9mdW4gPC0gZnVuY3Rpb24oZGF0YSkgewogIAogIGZ1bl8xIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIHBbMV0gLSBwWzJdLCBwWzNdKSAtIHBub3JtKHgsIHBbMV0gKyBwWzJdLCBwWzNdKQogIGZ1bl8yIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIHBbMV0gLSBwWzRdLCBwWzVdKSAtIHBub3JtKHgsIHBbMV0gKyBwWzRdLCBwWzVdKQogIAogIHBpbmkgPC0gbGlzdChwaW5pX29yaWdpbl9hc3ltLCBwaW5pX29yaWdpbl9hc3ltLCBwaW5pX3NjYWxlLCAKICAgICAgICAgICAgICAgcGluaV9vcmlnaW5fYXN5bSwgcGluaV9zY2FsZSkKCiAgZnVuX2RmIDwtIGRhdGEgJT4lIAogICAgZGlzdGluY3QocmVmZXJlbmNlcykgJT4lIAogICAgYXJyYW5nZShyZWZlcmVuY2VzKSAlPiUgCiAgICBiaW5kX2NvbHModGliYmxlKGZ1biA9IGMoZnVuXzEsIGZ1bl8yKSkpIAoKICBxdWlja3BzeShkYXRhLCBvcmllbnRhdGlvbiwgcmVzcG9uc2UsIGZ1biA9IGZ1bl9kZiwgeG1pbiA9IC00LCB4bWF4ID0gNCwKICAgICAgICAgICBwYXJpbmkgPSBwaW5pLCBib290c3RyYXAgPSAibm9uZSIsIGdyb3VwaW5nID0gLihyZWZlcmVuY2VzKSwKICAgICAgICAgICB0aHJlc2hvbGQgPSBGQUxTRSkKfQoKZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9zYW1lX2Z1biA8LSBmdW5jdGlvbihkYXRhKSB7CiAgCiAgZnVuXzEgPC0gZnVuY3Rpb24oeCwgcCkgcG5vcm0oeCwgcFsxXSAtIHBbMl0sIHBbM10pIC0gcG5vcm0oeCwgcFsxXSArIHBbMl0sIHBbM10pCiAgZnVuXzIgPC0gZnVuY3Rpb24oeCwgcCkgcG5vcm0oeCwgcFsxXSAtIHBbMl0sIHBbNF0pIC0gcG5vcm0oeCwgcFsxXSArIHBbMl0sIHBbNF0pCiAgCiAgcGluaSA8LSBsaXN0KHBpbmlfb3JpZ2luX2FzeW0sIHBpbmlfb3JpZ2luX2FzeW0sIHBpbmlfc2NhbGUsIAogICAgICAgICAgICAgICBwaW5pX3NjYWxlKQoKICBmdW5fZGYgPC0gZGF0YSAlPiUgCiAgICBkaXN0aW5jdChyZWZlcmVuY2VzKSAlPiUgCiAgICBhcnJhbmdlKHJlZmVyZW5jZXMpICU+JSAKICAgIGJpbmRfY29scyh0aWJibGUoZnVuID0gYyhmdW5fMSwgZnVuXzIpKSkgCgogIHF1aWNrcHN5KGRhdGEsIG9yaWVudGF0aW9uLCByZXNwb25zZSwgZnVuID0gZnVuX2RmLCB4bWluID0gLTQsIHhtYXggPSA0LAogICAgICAgICAgIHBhcmluaSA9IHBpbmksIGJvb3RzdHJhcCA9ICJub25lIiwgZ3JvdXBpbmcgPSAuKHJlZmVyZW5jZXMpLAogICAgICAgICAgIHRocmVzaG9sZCA9IEZBTFNFKQp9CgpmaXRfYXN5bV9mdWxsX3N5bV9jcml0X3NhbWVfemVyb19mdW4gPC0gZnVuY3Rpb24oZGF0YSkgewogIAogIGZ1bl8xIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIC0gcFsxXSwgcFsyXSkgLSBwbm9ybSh4LCBwWzFdLCBwWzJdKQogIGZ1bl8yIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIC0gcFsxXSwgcFszXSkgLSBwbm9ybSh4LCBwWzFdLCBwWzNdKQogIAogIHBpbmkgPC0gbGlzdChwaW5pX29yaWdpbl9hc3ltLCBwaW5pX3NjYWxlLCBwaW5pX3NjYWxlKQoKICBmdW5fZGYgPC0gZGF0YSAlPiUgCiAgICBkaXN0aW5jdChyZWZlcmVuY2VzKSAlPiUgCiAgICBhcnJhbmdlKHJlZmVyZW5jZXMpICU+JSAKICAgIGJpbmRfY29scyh0aWJibGUoZnVuID0gYyhmdW5fMSwgZnVuXzIpKSkgCgogIHF1aWNrcHN5KGRhdGEsIG9yaWVudGF0aW9uLCByZXNwb25zZSwgZnVuID0gZnVuX2RmLCB4bWluID0gLTQsIHhtYXggPSA0LAogICAgICAgICAgIHBhcmluaSA9IHBpbmksIGJvb3RzdHJhcCA9ICJub25lIiwgZ3JvdXBpbmcgPSAuKHJlZmVyZW5jZXMpLAogICAgICAgICAgIHRocmVzaG9sZCA9IEZBTFNFKQp9CgoKZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X2Z1biA8LSBmdW5jdGlvbihkYXRhKSB7CiAgCiAgZnVuXzEgPC0gZnVuY3Rpb24oeCwgcCkgcG5vcm0oeCwgcFsxXSAtIHBbMl0sIHBbM10pIC0gcG5vcm0oeCwgcFsxXSArIHBbMl0sIHBbM10pCiAgZnVuXzIgPC0gZnVuY3Rpb24oeCwgcCkgcG5vcm0oeCwgcFsxXSAtIHBbNF0sIHBbM10pIC0gcG5vcm0oeCwgcFsxXSArIHBbNF0sIHBbM10pCiAgCiAgcGluaSA8LSBsaXN0KHBpbmlfb3JpZ2luX2FzeW0sIHBpbmlfb3JpZ2luX2FzeW0sIHBpbmlfc2NhbGUsIAogICAgICAgICAgICAgICBwaW5pX29yaWdpbl9hc3ltKQoKICBmdW5fZGYgPC0gZGF0YSAlPiUgCiAgICBkaXN0aW5jdChyZWZlcmVuY2VzKSAlPiUgCiAgICBhcnJhbmdlKHJlZmVyZW5jZXMpICU+JSAKICAgIGJpbmRfY29scyh0aWJibGUoZnVuID0gYyhmdW5fMSwgZnVuXzIpKSkgCgogIHF1aWNrcHN5KGRhdGEsIG9yaWVudGF0aW9uLCByZXNwb25zZSwgZnVuID0gZnVuX2RmLCB4bWluID0gLTQsIHhtYXggPSA0LAogICAgICAgICAgIHBhcmluaSA9IHBpbmksIGJvb3RzdHJhcCA9ICJub25lIiwgZ3JvdXBpbmcgPSAuKHJlZmVyZW5jZXMpLAogICAgICAgICAgIHRocmVzaG9sZCA9IEZBTFNFKQp9CgpmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfemVyb19mdW4gPC0gZnVuY3Rpb24oZGF0YSkgewogIAogIGZ1bl8xIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIC0gcFsxXSwgcFsyXSkgLSBwbm9ybSh4LHBbMV0sIHBbMl0pCiAgZnVuXzIgPC0gZnVuY3Rpb24oeCwgcCkgcG5vcm0oeCwgLSBwWzNdLCBwWzJdKSAtIHBub3JtKHgsIHBbM10sIHBbMl0pCiAgCiAgcGluaSA8LSBsaXN0KHBpbmlfb3JpZ2luX2FzeW0sIHBpbmlfc2NhbGUsIAogICAgICAgICAgICAgICBwaW5pX29yaWdpbl9hc3ltKQoKICBmdW5fZGYgPC0gZGF0YSAlPiUgCiAgICBkaXN0aW5jdChyZWZlcmVuY2VzKSAlPiUgCiAgICBhcnJhbmdlKHJlZmVyZW5jZXMpICU+JSAKICAgIGJpbmRfY29scyh0aWJibGUoZnVuID0gYyhmdW5fMSwgZnVuXzIpKSkgCgogIHF1aWNrcHN5KGRhdGEsIG9yaWVudGF0aW9uLCByZXNwb25zZSwgZnVuID0gZnVuX2RmLCB4bWluID0gLTQsIHhtYXggPSA0LAogICAgICAgICAgIHBhcmluaSA9IHBpbmksIGJvb3RzdHJhcCA9ICJub25lIiwgZ3JvdXBpbmcgPSAuKHJlZmVyZW5jZXMpLAogICAgICAgICAgIHRocmVzaG9sZCA9IEZBTFNFKQp9CgpmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV9mdW4gPC0gZnVuY3Rpb24oZGF0YSkgewogIAogIGZ1bl8xIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIHBbMV0gLSBwWzJdLCBwWzNdKSAtIHBub3JtKHgsIHBbMV0gKyBwWzJdLCBwWzNdKQogIGZ1bl8yIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIHBbMV0gLSBwWzJdLCBwWzNdKSAtIHBub3JtKHgsIHBbMV0gKyBwWzJdLCBwWzNdKQogIAogIHBpbmkgPC0gbGlzdChwaW5pX29yaWdpbl9hc3ltLCBwaW5pX29yaWdpbl9hc3ltLCBwaW5pX3NjYWxlKQoKICBmdW5fZGYgPC0gZGF0YSAlPiUgCiAgICBkaXN0aW5jdChyZWZlcmVuY2VzKSAlPiUgCiAgICBhcnJhbmdlKHJlZmVyZW5jZXMpICU+JSAKICAgIGJpbmRfY29scyh0aWJibGUoZnVuID0gYyhmdW5fMSwgZnVuXzIpKSkgCgogIHF1aWNrcHN5KGRhdGEsIG9yaWVudGF0aW9uLCByZXNwb25zZSwgZnVuID0gZnVuX2RmLCB4bWluID0gLTQsIHhtYXggPSA0LAogICAgICAgICAgIHBhcmluaSA9IHBpbmksIGJvb3RzdHJhcCA9ICJub25lIiwgZ3JvdXBpbmcgPSAuKHJlZmVyZW5jZXMpLAogICAgICAgICAgIHRocmVzaG9sZCA9IEZBTFNFKQp9CgpmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV96ZXJvX2Z1biA8LSBmdW5jdGlvbihkYXRhKSB7CiAgCiAgZnVuXzEgPC0gZnVuY3Rpb24oeCwgcCkgcG5vcm0oeCwgLSBwWzFdLCBwWzJdKSAtIHBub3JtKHgsIHBbMV0sIHBbMl0pCiAgZnVuXzIgPC0gZnVuY3Rpb24oeCwgcCkgcG5vcm0oeCwgLSBwWzFdLCBwWzJdKSAtIHBub3JtKHgsIHBbMV0sIHBbMl0pCiAgCiAgcGluaSA8LSBsaXN0KHBpbmlfb3JpZ2luX2FzeW0sIHBpbmlfc2NhbGUpCgogIGZ1bl9kZiA8LSBkYXRhICU+JSAKICAgIGRpc3RpbmN0KHJlZmVyZW5jZXMpICU+JSAKICAgIGFycmFuZ2UocmVmZXJlbmNlcykgJT4lIAogICAgYmluZF9jb2xzKHRpYmJsZShmdW4gPSBjKGZ1bl8xLCBmdW5fMikpKSAKCiAgcXVpY2twc3koZGF0YSwgb3JpZW50YXRpb24sIHJlc3BvbnNlLCBmdW4gPSBmdW5fZGYsIHhtaW4gPSAtNCwgeG1heCA9IDQsCiAgICAgICAgICAgcGFyaW5pID0gcGluaSwgYm9vdHN0cmFwID0gIm5vbmUiLCBncm91cGluZyA9IC4ocmVmZXJlbmNlcyksCiAgICAgICAgICAgdGhyZXNob2xkID0gRkFMU0UpCn0KCmZpdF9hc3ltX2Z1bGxfZnVuX3plcm8gPC0gZnVuY3Rpb24oZGF0YSkgewogIAogIGZ1bl8xIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIC0gcFsxXSwgcFsyXSkgLSBwbm9ybSh4LCBwWzFdLCBwWzJdKQogIGZ1bl8yIDwtIGZ1bmN0aW9uKHgsIHApIHBub3JtKHgsIC0gcFszXSwgcFs0XSkgLSBwbm9ybSh4LCBwWzNdLCBwWzRdKQogIAogIHBpbmkgPC0gbGlzdChwaW5pX29yaWdpbl9hc3ltLCBwaW5pX3NjYWxlLCAKICAgICAgICAgICAgICAgcGluaV9vcmlnaW5fYXN5bSwgcGluaV9zY2FsZSkKCiAgZnVuX2RmIDwtIGRhdGEgJT4lIAogICAgZGlzdGluY3QocmVmZXJlbmNlcykgJT4lIAogICAgYXJyYW5nZShyZWZlcmVuY2VzKSAlPiUgCiAgICBiaW5kX2NvbHModGliYmxlKGZ1biA9IGMoZnVuXzEsIGZ1bl8yKSkpIAoKICBxdWlja3BzeShkYXRhLCBvcmllbnRhdGlvbiwgcmVzcG9uc2UsIGZ1biA9IGZ1bl9kZiwgeG1pbiA9IC00LCB4bWF4ID0gNCwKICAgICAgICAgICBwYXJpbmkgPSBwaW5pLCBib290c3RyYXAgPSAibm9uZSIsIGdyb3VwaW5nID0gLihyZWZlcmVuY2VzKSwKICAgICAgICAgICB0aHJlc2hvbGQgPSBGQUxTRSkKfQoKCgoKZml0X2FzeW1fYmVzdCA8LSBkYXRfYXN5bSAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICBuZXN0KCkgJT4lIAogIG11dGF0ZShmaXRfYXN5bV9mdWxsID0gbWFwKGRhdGEsIGZpdF9hc3ltX2Z1bGxfZnVuKSwKICAgICAgICAgZml0X2FzeW1fZnVsbF9zeW1fY3JpdCA9IG1hcChkYXRhLCBmaXRfYXN5bV9mdWxsX3N5bV9jcml0X2Z1biksCiAgICAgICAgIGZpdF9hc3ltX2Z1bGxfc3ltX2NyaXRfc2FtZSA9IG1hcChkYXRhLCBmaXRfYXN5bV9mdWxsX3N5bV9jcml0X3NhbWVfZnVuKSwKICAgICAgICAgZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9zYW1lX3plcm8gPSBtYXAoZGF0YSwgZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9zYW1lX3plcm9fZnVuKSwKICAgICAgICAgZml0X2FzeW1fZnVsbF96ZXJvID0gbWFwKGRhdGEsIGZpdF9hc3ltX2Z1bGxfZnVuX3plcm8pLAogICAgICAgICBmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGUgPSBtYXAoZGF0YSwgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX2Z1biksCiAgICAgICAgIGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdCA9IG1hcChkYXRhLCBmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfZnVuKSwKICAgICAgICAgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3plcm8gPSBtYXAoZGF0YSwgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3plcm9fZnVuKSwKICAgICAgICAgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUgPSBtYXAoZGF0YSwgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfZnVuKSwKICAgICAgICAgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfemVybyA9IG1hcChkYXRhLCBmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV96ZXJvX2Z1bikpICU+JSAKICAgICAgIyAgIGZpdF9hc3ltX3plcm8gPSBtYXAoZGF0YSwgZml0X2FzeW1femVyb19mdW4pLAogICAgICAgIyAgZml0X2FzeW1fcCA9IG1hcChkYXRhLCBmaXRfYXN5bV9wX2Z1biksCiAgICAgICAjICBmaXRfYXN5bV9kID0gbWFwKGRhdGEsIGZpdF9hc3ltX2RfZnVuKSkgJT4lIAogIHNlbGVjdCgtZGF0YSkKYGBgCgojIyMgRnVsbApgYGB7ciBmaWcuaGVpZ2h0PTE4LCBmaWcud2lkdGg9MTV9CmdncGxvdCgpICsgZmFjZXRfd3JhcChzdWJqZWN0IH4gdmVydGljYWwsIG5jb2wgPSA2KSArCiAgZ2VvbV9wb2ludChkYXRhID0gZml0X2FzeW1fYmVzdCAlPiUgCiAgICAgICAgICAgICAgIG11dGF0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGwsICJhdmVyYWdlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICAgYWVzKHggPSBvcmllbnRhdGlvbiwgeSA9IHByb2IsIGNvbG9yID0gcmVmZXJlbmNlcykpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpdF9hc3ltX2Jlc3QgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsLCAiY3VydmVzIikpICU+JSAKICAgICAgICAgICAgICAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsLCB0ZW1wKSAlPiUgCiAgICAgICAgICAgICAgIHVubmVzdCh0ZW1wKSwgCiAgICAgICAgICAgIGFlcyh4ID0geCwgeSA9IHksIGNvbG9yID0gcmVmZXJlbmNlcykpICsKICB0aGVtZV9ncmV5KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgCmBgYAoKIyMjIEZ1bGwgc2FtZSBzbG9wZQpgYGB7ciBmaWcuaGVpZ2h0PTE4LCBmaWcud2lkdGg9MTV9CmdncGxvdCgpICsgZmFjZXRfd3JhcChzdWJqZWN0IH4gdmVydGljYWwsIG5jb2wgPSA2KSArCiAgZ2VvbV9wb2ludChkYXRhID0gZml0X2FzeW1fYmVzdCAlPiUgCiAgICAgICAgICAgICAgIG11dGF0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZSwgImF2ZXJhZ2VzIikpICU+JSAKICAgICAgICAgICAgICAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsLCB0ZW1wKSAlPiUgCiAgICAgICAgICAgICAgIHVubmVzdCh0ZW1wKSwgCiAgICAgICAgICAgICBhZXMoeCA9IG9yaWVudGF0aW9uLCB5ID0gcHJvYiwgY29sb3IgPSByZWZlcmVuY2VzKSkgKwogIGdlb21fbGluZShkYXRhID0gZml0X2FzeW1fYmVzdCAlPiUgCiAgICAgICAgICAgICAgIG11dGF0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZSwgImN1cnZlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICBhZXMoeCA9IHgsIHkgPSB5LCBjb2xvciA9IHJlZmVyZW5jZXMpKSArCiAgdGhlbWVfZ3JleSgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpIApgYGAKCiMjIyBGdWxsIHZzIGZ1bGwgc2FtZSBzbG9wZSAKCmBgYHtyfQphc3ltX2Z1bGxfdnNfZnVsbF9zYW1lX3Nsb3BlIDwtIGZpdF9hc3ltX2Jlc3QgJT4lIAogIGdyb3VwX2J5KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgdHJhbnNtdXRlKGZpdF9hc3ltX2Z1bGxfbG9nbGlrID0gbWFwKGZpdF9hc3ltX2Z1bGwsICJsb2dsaWtzIiksCiAgICAgICAgIGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9sb2dsaWsgPSBtYXAoZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlLCAibG9nbGlrcyIpLAogICAgICAgICBiZXN0ID0gbWFwMl9jaHIoZml0X2FzeW1fZnVsbF9sb2dsaWssIGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9sb2dsaWssIAogICAgICAgICAgICAgICAgICAgIH5tb2RlbF9zZWxlY3Rpb25fbHJ0KC54LCAueSkkYmVzdCkpCgphc3ltX2Z1bGxfdnNfZnVsbF9zYW1lX3Nsb3BlICU+JSAKICBncm91cF9ieShiZXN0KSAlPiUgCiAgY291bnQoKSAgICAgCiAgICAgICAgIApiZXN0X2FzeW1fZnVsbF9ub19zYW1lX3Nsb3BlIDwtIGFzeW1fZnVsbF92c19mdWxsX3NhbWVfc2xvcGUgJT4lIAogIGZpbHRlcihiZXN0ID09ICJmaXJzdCIpICU+JSAKICBzZWxlY3Qoc3ViamVjdCwgdmVydGljYWwpCgpiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlIDwtIGFzeW1fZnVsbF92c19mdWxsX3NhbWVfc2xvcGUgJT4lIAogIGZpbHRlcihiZXN0ID09ICJzZWNvbmQiKSAlPiUgCiAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsKQpgYGAKCgoKIyMjIEZ1bGwgbm8gc2FtZSBzbG9wZSBzeW0gY3JpdAoKYGBge3IgZmlnLmhlaWdodD0xOCwgZmlnLndpZHRoPTE1fQpnZ3Bsb3QoKSArIGZhY2V0X3dyYXAoc3ViamVjdCB+IHZlcnRpY2FsLCBuY29sID0gNikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpdF9hc3ltX2Jlc3QgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3N5bV9jcml0LCAiYXZlcmFnZXMiKSkgJT4lIAogICAgICAgICAgICAgICBzZWxlY3Qoc3ViamVjdCwgdmVydGljYWwsIHRlbXApICU+JSAKICAgICAgICAgICAgICAgdW5uZXN0KHRlbXApLCAKICAgICAgICAgICAgIGFlcyh4ID0gb3JpZW50YXRpb24sIHkgPSBwcm9iLCBjb2xvciA9IHJlZmVyZW5jZXMpKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBmaXRfYXN5bV9iZXN0ICU+JSAKICAgICAgICAgICAgICAgbXV0YXRlKHRlbXAgPSBtYXAoZml0X2FzeW1fZnVsbF9zeW1fY3JpdCwgImN1cnZlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICBhZXMoeCA9IHgsIHkgPSB5LCBjb2xvciA9IHJlZmVyZW5jZXMpKSArCiAgdGhlbWVfZ3JleSgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpIApgYGAKCiMjIyBGdWxsIG5vIHNhbWUgc2xvcGUgdnMgZnVsbCBubyBzYW1lIHNsb3BlIHN5bSBjcml0IAoKYGBge3J9CmFzeW1fZnVsbF9ub19zYW1lX3Nsb3BlX3ZzX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdCA8LSBmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZShmaXRfYXN5bV9mdWxsX2xvZ2xpayA9IG1hcChmaXRfYXN5bV9mdWxsLCAibG9nbGlrcyIpLAogICAgICAgICBmaXRfYXN5bV9mdWxsX3N5bV9jcml0X2xvZ2xpayA9IG1hcChmaXRfYXN5bV9mdWxsX3N5bV9jcml0LCAibG9nbGlrcyIpLAogICAgICAgICBiZXN0ID0gbWFwMl9jaHIoZml0X2FzeW1fZnVsbF9sb2dsaWssIGZpdF9hc3ltX2Z1bGxfc3ltX2NyaXRfbG9nbGlrLCAKICAgICAgICAgICAgICAgICAgICB+bW9kZWxfc2VsZWN0aW9uX2xydCgueCwgLnkpJGJlc3QpKQoKYXN5bV9mdWxsX25vX3NhbWVfc2xvcGVfdnNfZnVsbF9ub19zYW1lX3Nsb3BlX3N5bV9jcml0ICU+JSAKICBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfbm9fc2FtZV9zbG9wZSkgJT4lIAogIGdyb3VwX2J5KGJlc3QpICU+JSAKICBjb3VudCgpICAgICAKICAgICAgICAgCgpiZXN0X2FzeW1fZnVsbF9ub19zYW1lX3Nsb3BlX3N5bV9jcml0IDwtIGFzeW1fZnVsbF9ub19zYW1lX3Nsb3BlX3ZzX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdCAlPiUgCiAgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX25vX3NhbWVfc2xvcGUpICU+JSAKICBmaWx0ZXIoYmVzdCA9PSAic2Vjb25kIikgJT4lIAogIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCkKYGBgCgojIyMgRnVsbCBubyBzYW1lIHNsb3BlIHN5bSBjcml0IHNhbWUgCgpgYGB7ciBmaWcuaGVpZ2h0PTE4LCBmaWcud2lkdGg9MTV9CmdncGxvdCgpICsgZmFjZXRfd3JhcChzdWJqZWN0IH4gdmVydGljYWwsIG5jb2wgPSA2KSArCiAgZ2VvbV9wb2ludChkYXRhID0gZml0X2FzeW1fYmVzdCAlPiUgCiAgICAgICAgICAgICAgIG11dGF0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGxfc3ltX2NyaXRfc2FtZSwgImF2ZXJhZ2VzIikpICU+JSAKICAgICAgICAgICAgICAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsLCB0ZW1wKSAlPiUgCiAgICAgICAgICAgICAgIHVubmVzdCh0ZW1wKSwgCiAgICAgICAgICAgICBhZXMoeCA9IG9yaWVudGF0aW9uLCB5ID0gcHJvYiwgY29sb3IgPSByZWZlcmVuY2VzKSkgKwogIGdlb21fbGluZShkYXRhID0gZml0X2FzeW1fYmVzdCAlPiUgCiAgICAgICAgICAgICAgIG11dGF0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGxfc3ltX2NyaXRfc2FtZSwgImN1cnZlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICBhZXMoeCA9IHgsIHkgPSB5LCBjb2xvciA9IHJlZmVyZW5jZXMpKSArCiAgdGhlbWVfZ3JleSgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpIApgYGAKCiMjIyBGdWxsIG5vIHNhbWUgc2xvcGUgc3ltIGNyaXQgdnMgZnVsbCBubyBzYW1lIHNsb3BlIHN5bSBjcml0IHNhbWUgCgpgYGB7cn0KYXN5bV9mdWxsX25vX3NhbWVfc2xvcGVfc3ltX2NyaXRfdnNfZnVsbF9ub19zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUgPC0gZml0X2FzeW1fYmVzdCAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICB0cmFuc211dGUoZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9sb2dsaWsgPSBtYXAoZml0X2FzeW1fZnVsbF9zeW1fY3JpdCwgImxvZ2xpa3MiKSwKICAgICAgICAgZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9zYW1lX2xvZ2xpayA9IG1hcChmaXRfYXN5bV9mdWxsX3N5bV9jcml0X3NhbWUsICJsb2dsaWtzIiksCiAgICAgICAgIGJlc3QgPSBtYXAyX2NocihmaXRfYXN5bV9mdWxsX3N5bV9jcml0X2xvZ2xpaywgZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9zYW1lX2xvZ2xpaywgCiAgICAgICAgICAgICAgICAgICAgfm1vZGVsX3NlbGVjdGlvbl9scnQoLngsIC55KSRiZXN0KSkKCmFzeW1fZnVsbF9ub19zYW1lX3Nsb3BlX3N5bV9jcml0X3ZzX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lICU+JSAKICBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdCkgJT4lIAogIGdyb3VwX2J5KGJlc3QpICU+JSAKICBjb3VudCgpICAgICAKICAgICAgICAgCgpiZXN0X2FzeW1fZnVsbF9ub19zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUgPC0gYXN5bV9mdWxsX25vX3NhbWVfc2xvcGVfc3ltX2NyaXRfdnNfZnVsbF9ub19zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUgJT4lIAogIHNlbWlfam9pbihiZXN0X2FzeW1fZnVsbF9ub19zYW1lX3Nsb3BlX3N5bV9jcml0KSAlPiUgCiAgZmlsdGVyKGJlc3QgPT0gInNlY29uZCIpICU+JSAKICBzZWxlY3Qoc3ViamVjdCwgdmVydGljYWwpCmBgYAoKIyMjIEZ1bGwgbm8gc2FtZSBzbG9wZSBzeW0gY3JpdCBzYW1lIHplcm8KCmBgYHtyIGZpZy5oZWlnaHQ9MTgsIGZpZy53aWR0aD0xNX0KZ2dwbG90KCkgKyBmYWNldF93cmFwKHN1YmplY3QgfiB2ZXJ0aWNhbCwgbmNvbCA9IDYpICsKICBnZW9tX3BvaW50KGRhdGEgPSBmaXRfYXN5bV9iZXN0ICU+JSAKICAgICAgICAgICAgICAgbXV0YXRlKHRlbXAgPSBtYXAoZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9zYW1lX3plcm8sICJhdmVyYWdlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICAgYWVzKHggPSBvcmllbnRhdGlvbiwgeSA9IHByb2IsIGNvbG9yID0gcmVmZXJlbmNlcykpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpdF9hc3ltX2Jlc3QgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3N5bV9jcml0X3NhbWVfemVybywgImN1cnZlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICBhZXMoeCA9IHgsIHkgPSB5LCBjb2xvciA9IHJlZmVyZW5jZXMpKSArCiAgdGhlbWVfZ3JleSgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpIApgYGAKCiMjIyBGdWxsIG5vIHNhbWUgc2xvcGUgc3ltIGNyaXQgc2FtZSB2cyBmdWxsIG5vIHNhbWUgc2xvcGUgc3ltIGNyaXQgc2FtZSB6ZXJvCgpgYGB7cn0KYXN5bV9mdWxsX25vX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV92c19mdWxsX25vX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV96ZXJvIDwtIGZpdF9hc3ltX2Jlc3QgJT4lIAogIGdyb3VwX2J5KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgdHJhbnNtdXRlKGZpdF9hc3ltX2Z1bGxfc3ltX2NyaXRfc2FtZV9sb2dsaWsgPSBtYXAoZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9zYW1lLCAibG9nbGlrcyIpLAogICAgICAgICBmaXRfYXN5bV9mdWxsX3N5bV9jcml0X3NhbWVfemVyb19sb2dsaWsgPSBtYXAoZml0X2FzeW1fZnVsbF9zeW1fY3JpdF9zYW1lX3plcm8sICJsb2dsaWtzIiksCiAgICAgICAgIGJlc3QgPSBtYXAyX2NocihmaXRfYXN5bV9mdWxsX3N5bV9jcml0X3NhbWVfbG9nbGlrLCBmaXRfYXN5bV9mdWxsX3N5bV9jcml0X3NhbWVfemVyb19sb2dsaWssIAogICAgICAgICAgICAgICAgICAgIH5tb2RlbF9zZWxlY3Rpb25fbHJ0KC54LCAueSkkYmVzdCkpCgphc3ltX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3ZzX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3plcm8gJT4lIAogIHNlbWlfam9pbihiZXN0X2FzeW1fZnVsbF9ub19zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUpICU+JSAKICBncm91cF9ieShiZXN0KSAlPiUgCiAgY291bnQoKSAgICAgCiAgICAgICAgIAojIyMgQWRkIHRvIHMgdnMgZApiZXN0X2FzeW1fZnVsbF9ub19zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfbm9femVybyA8LSBhc3ltX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3ZzX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3plcm8gJT4lCiAgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX25vX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZSkgJT4lIAogIGZpbHRlcihiZXN0ID09ICJmaXJzdCIpICU+JSAKICBzZWxlY3Qoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICBtdXRhdGUoYmVzdCA9ICJyZXNwb25zZSIpCmBgYAoKIyMjIEZ1bGwgc2FtZSBzbG9wZSBzeW0gY3JpdAoKYGBge3IgZmlnLmhlaWdodD0xOCwgZmlnLndpZHRoPTE1fQpnZ3Bsb3QoKSArIGZhY2V0X3dyYXAoc3ViamVjdCB+IHZlcnRpY2FsLCBuY29sID0gNikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpdF9hc3ltX2Jlc3QgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXQsICJhdmVyYWdlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICAgYWVzKHggPSBvcmllbnRhdGlvbiwgeSA9IHByb2IsIGNvbG9yID0gcmVmZXJlbmNlcykpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpdF9hc3ltX2Jlc3QgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXQsICJjdXJ2ZXMiKSkgJT4lIAogICAgICAgICAgICAgICBzZWxlY3Qoc3ViamVjdCwgdmVydGljYWwsIHRlbXApICU+JSAKICAgICAgICAgICAgICAgdW5uZXN0KHRlbXApLCAKICAgICAgICAgICAgYWVzKHggPSB4LCB5ID0geSwgY29sb3IgPSByZWZlcmVuY2VzKSkgKwogIHRoZW1lX2dyZXkoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSAKYGBgCgoKIyMjIEZ1bGwgc2FtZSBzbG9wZSB2cyBmdWxsIHNhbWUgc2xvcGUgc3ltIGNyaXQgCgpgYGB7cn0KYXN5bV9mdWxsX3NhbWVfc2xvcGVfdnNfZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0IDwtIGZpdF9hc3ltX2Jlc3QgJT4lIAogIGdyb3VwX2J5KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgdHJhbnNtdXRlKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9sb2dsaWsgPSBtYXAoZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlLCAibG9nbGlrcyIpLAogICAgICAgICBmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfbG9nbGlrID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdCwgImxvZ2xpa3MiKSwKICAgICAgICAgYmVzdCA9IG1hcDJfY2hyKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9sb2dsaWssIGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9sb2dsaWssIAogICAgICAgICAgICAgICAgICAgIH5tb2RlbF9zZWxlY3Rpb25fbHJ0KC54LCAueSkkYmVzdCkpCgphc3ltX2Z1bGxfc2FtZV9zbG9wZV92c19mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXQgJT4lIAogIHNlbWlfam9pbihiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlKSAlPiUgCiAgZ3JvdXBfYnkoYmVzdCkgJT4lIAogIGNvdW50KCkgICAgIAogICAgICAgICAKIyMjIEFkZCB0byBzIHZzIGQKYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9ub19zeW1fY3JpdCA8LSBhc3ltX2Z1bGxfc2FtZV9zbG9wZV92c19mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXQgJT4lCiAgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX3NhbWVfc2xvcGUpICU+JSAKICBmaWx0ZXIoYmVzdCA9PSAiZmlyc3QiKSAlPiUgCiAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgbXV0YXRlKGJlc3QgPSAibm8gc3ltIGNyaXQiKQoKYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdCA8LSBhc3ltX2Z1bGxfc2FtZV9zbG9wZV92c19mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXQgJT4lCiAgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX3NhbWVfc2xvcGUpICU+JSAKICBmaWx0ZXIoYmVzdCA9PSAic2Vjb25kIikgJT4lIAogIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCkgCmBgYAoKIyMjIEZ1bGwgc2FtZSBzbG9wZSBzeW0gY3JpdCBzYW1lIAoKYGBge3IgZmlnLmhlaWdodD0xOCwgZmlnLndpZHRoPTE1fQpnZ3Bsb3QoKSArIGZhY2V0X3dyYXAoc3ViamVjdCB+IHZlcnRpY2FsLCBuY29sID0gNikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpdF9hc3ltX2Jlc3QgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZSwgImF2ZXJhZ2VzIikpICU+JSAKICAgICAgICAgICAgICAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsLCB0ZW1wKSAlPiUgCiAgICAgICAgICAgICAgIHVubmVzdCh0ZW1wKSwgCiAgICAgICAgICAgICBhZXMoeCA9IG9yaWVudGF0aW9uLCB5ID0gcHJvYiwgY29sb3IgPSByZWZlcmVuY2VzKSkgKwogIGdlb21fbGluZShkYXRhID0gZml0X2FzeW1fYmVzdCAlPiUgCiAgICAgICAgICAgICAgIG11dGF0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lLCAiY3VydmVzIikpICU+JSAKICAgICAgICAgICAgICAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsLCB0ZW1wKSAlPiUgCiAgICAgICAgICAgICAgIHVubmVzdCh0ZW1wKSwgCiAgICAgICAgICAgIGFlcyh4ID0geCwgeSA9IHksIGNvbG9yID0gcmVmZXJlbmNlcykpICsKICB0aGVtZV9ncmV5KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgCmBgYAoKCiMjIyBGdWxsIHNhbWUgc2xvcGUgc3ltIGNyaXQgdnMgZnVsbCBzYW1lIHNsb3BlIHN5bSBjcml0IHNhbWUKCmBgYHtyfQphc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF92c19mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZSA8LSBmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZShmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfbG9nbGlrID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdCwgImxvZ2xpa3MiKSwKICAgICAgICAgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfbG9nbGlrID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lLCAibG9nbGlrcyIpLAogICAgICAgICBiZXN0ID0gbWFwMl9jaHIoZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X2xvZ2xpaywgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfbG9nbGlrLCAKICAgICAgICAgICAgICAgICAgICB+bW9kZWxfc2VsZWN0aW9uX2xydCgueCwgLnkpJGJlc3QpKQoKYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfdnNfZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUgJT4lIAogIHNlbWlfam9pbihiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0KSAlPiUgCiAgZ3JvdXBfYnkoYmVzdCkgJT4lIAogIGNvdW50KCkgICAgIAogICAgICAgICAKYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9ub19zYW1lIDwtIGFzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3ZzX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lICU+JQogIHNlbWlfam9pbihiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0KSAlPiUgCiAgZmlsdGVyKGJlc3QgPT0gImZpcnN0IikgJT4lIAogIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCkgCgpiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUgPC0gYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfdnNfZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUgJT4lCiAgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXQpICU+JSAKICBmaWx0ZXIoYmVzdCA9PSAic2Vjb25kIikgJT4lIAogIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCkgCmBgYAoKIyMjIEZ1bGwgc2FtZSBzbG9wZSBzeW0gY3JpdCBubyBzYW1lIHplcm8KCmBgYHtyIGZpZy5oZWlnaHQ9MTgsIGZpZy53aWR0aD0xNX0KZ2dwbG90KCkgKyBmYWNldF93cmFwKHN1YmplY3QgfiB2ZXJ0aWNhbCwgbmNvbCA9IDYpICsKICBnZW9tX3BvaW50KGRhdGEgPSBmaXRfYXN5bV9iZXN0ICU+JSAKICAgICAgICAgICAgICAgbXV0YXRlKHRlbXAgPSBtYXAoZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3plcm8sICJhdmVyYWdlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICAgYWVzKHggPSBvcmllbnRhdGlvbiwgeSA9IHByb2IsIGNvbG9yID0gcmVmZXJlbmNlcykpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpdF9hc3ltX2Jlc3QgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfemVybywgImN1cnZlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICBhZXMoeCA9IHgsIHkgPSB5LCBjb2xvciA9IHJlZmVyZW5jZXMpKSArCiAgdGhlbWVfZ3JleSgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpIApgYGAKCiMjIyBGdWxsIHNhbWUgc2xvcGUgc3ltIGNyaXQgbm8gc2FtZSB2cyBmdWxsIHNhbWUgc2xvcGUgc3ltIGNyaXQgbm8gc2FtZSB6ZXJvIAoKYGBge3J9CmFzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X25vX3NhbWVfdnNfZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X25vX3NhbWVfemVybyA8LSBmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZShmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfbG9nbGlrID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdCwgImxvZ2xpa3MiKSwKICAgICAgICAgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3plcm9fbG9nbGlrID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF96ZXJvLCAibG9nbGlrcyIpLAogICAgICAgICBiZXN0ID0gbWFwMl9jaHIoZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X2xvZ2xpaywgZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3plcm9fbG9nbGlrLCAKICAgICAgICAgICAgICAgICAgICB+bW9kZWxfc2VsZWN0aW9uX2xydCgueCwgLnkpJGJlc3QpKQoKYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfbm9fc2FtZV92c19mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfbm9fc2FtZV96ZXJvICU+JSAKICBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9ub19zYW1lKSAlPiUgCiAgZ3JvdXBfYnkoYmVzdCkgJT4lIAogIGNvdW50KCkgICAgIAogICAgICAgICAKIyMjIEFkZCB0byBzIHZzIGQKYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9ub19zYW1lX25vX3plcm8gPC0gYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfbm9fc2FtZV92c19mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfbm9fc2FtZV96ZXJvICU+JQogIHNlbWlfam9pbihiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X25vX3NhbWUpICU+JSAKICBmaWx0ZXIoYmVzdCA9PSAiZmlyc3QiKSAlPiUgCiAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgbXV0YXRlKGJlc3QgPSAicmVzcG9uc2UiKQoKYGBgCgojIyMgRnVsbCBzYW1lIHNsb3BlIHN5bSBjcml0IHNhbWUgemVybwoKYGBge3IgZmlnLmhlaWdodD0xOCwgZmlnLndpZHRoPTE1fQpnZ3Bsb3QoKSArIGZhY2V0X3dyYXAoc3ViamVjdCB+IHZlcnRpY2FsLCBuY29sID0gNikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpdF9hc3ltX2Jlc3QgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV96ZXJvLCAiYXZlcmFnZXMiKSkgJT4lIAogICAgICAgICAgICAgICBzZWxlY3Qoc3ViamVjdCwgdmVydGljYWwsIHRlbXApICU+JSAKICAgICAgICAgICAgICAgdW5uZXN0KHRlbXApLCAKICAgICAgICAgICAgIGFlcyh4ID0gb3JpZW50YXRpb24sIHkgPSBwcm9iLCBjb2xvciA9IHJlZmVyZW5jZXMpKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBmaXRfYXN5bV9iZXN0ICU+JSAKICAgICAgICAgICAgICAgbXV0YXRlKHRlbXAgPSBtYXAoZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfemVybywgImN1cnZlcyIpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChzdWJqZWN0LCB2ZXJ0aWNhbCwgdGVtcCkgJT4lIAogICAgICAgICAgICAgICB1bm5lc3QodGVtcCksIAogICAgICAgICAgICBhZXMoeCA9IHgsIHkgPSB5LCBjb2xvciA9IHJlZmVyZW5jZXMpKSArCiAgdGhlbWVfZ3JleSgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpIApgYGAKCiMjIyBGdWxsIHNhbWUgc2xvcGUgc3ltIGNyaXQgc2FtZSB2cyBmdWxsIHNhbWUgc2xvcGUgc3ltIGNyaXQgc2FtZSB6ZXJvIAoKYGBge3J9CmFzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfdnNfZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfemVybyA8LSBmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZShmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV9sb2dsaWsgPSBtYXAoZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUsICJsb2dsaWtzIiksCiAgICAgICAgIGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3plcm9fbG9nbGlrID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3plcm8sICJsb2dsaWtzIiksCiAgICAgICAgIGJlc3QgPSBtYXAyX2NocihmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV9sb2dsaWssIGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3plcm9fbG9nbGlrLCAKICAgICAgICAgICAgICAgICAgICB+bW9kZWxfc2VsZWN0aW9uX2xydCgueCwgLnkpJGJlc3QpKQoKYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV92c19mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV96ZXJvICU+JSAKICBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lKSAlPiUgCiAgZ3JvdXBfYnkoYmVzdCkgJT4lIAogIGNvdW50KCkgICAgIAogICAgICAgICAKIyMjIEFkZCB0byBzIHZzIGQKYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX25vX3plcm8gPC0gYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV92c19mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV96ZXJvICU+JQogIHNlbWlfam9pbihiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWUpICU+JSAKICBmaWx0ZXIoYmVzdCA9PSAiZmlyc3QiKSAlPiUgCiAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgbXV0YXRlKGJlc3QgPSAic2Vuc29yeSIpCgojIyMgQWRkIHRvIHMgdnMgZApiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfemVybyA8LSBhc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3ZzX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3plcm8gJT4lCiAgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZSkgJT4lIAogIGZpbHRlcihiZXN0ID09ICJzZWNvbmQiKSAlPiUgCiAgc2VsZWN0KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgbXV0YXRlKGJlc3QgPSAiemVybyIpCgpgYGAKCiMjIyBBdmVyYWdlcywgY3VydmVzIGFuZCBwYXJhbWV0ZXJzIApgYGB7ciBmaWcuaGVpZ2h0PTIwLCBmaWcud2lkdGg9MTV9CgoKZml0X2FzeW1fYmVzdCAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICB0cmFuc211dGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3N5bV9jcml0X3NhbWUsICJhdmVyYWdlcyIpKSAlPiUgCiAgdW5uZXN0KHRlbXApCiAgCiAgCmFzeW1fYXZlcmFnZXNfc192c19kIDwtIAogIChmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGwsICJhdmVyYWdlcyIpKSAlPiUgCiAgdW5uZXN0KHRlbXApICU+JSBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX25vX3plcm8pKSAlPiUgCiAgYmluZF9yb3dzKChmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZSwgImF2ZXJhZ2VzIikpICU+JSAKICB1bm5lc3QodGVtcCkgJT4lIHNlbWlfam9pbihiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX25vX3N5bV9jcml0KSkpICU+JSAKICBiaW5kX3Jvd3MoKGZpdF9hc3ltX2Jlc3QgJT4lIAogIGdyb3VwX2J5KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgdHJhbnNtdXRlKHRlbXAgPSBtYXAoZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlLCAiYXZlcmFnZXMiKSkgJT4lIAogIHVubmVzdCh0ZW1wKSAlPiUgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfbm9fc2FtZV9ub196ZXJvKSkpICU+JSAgIAogIGJpbmRfcm93cygoZml0X2FzeW1fYmVzdCAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICB0cmFuc211dGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGUsICJhdmVyYWdlcyIpKSAlPiUgCiAgdW5uZXN0KHRlbXApICU+JSBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX25vX3plcm8pKSkgJT4lIAogIGJpbmRfcm93cygoZml0X2FzeW1fYmVzdCAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICB0cmFuc211dGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGUsICJhdmVyYWdlcyIpKSAlPiUgCiAgdW5uZXN0KHRlbXApICU+JSBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3plcm8pKSkgCgphc3ltX2N1cnZlc19zX3ZzX2QgPC0gCiAgKGZpdF9hc3ltX2Jlc3QgJT4lIAogIGdyb3VwX2J5KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgdHJhbnNtdXRlKHRlbXAgPSBtYXAoZml0X2FzeW1fZnVsbCwgImN1cnZlcyIpKSAlPiUgCiAgdW5uZXN0KHRlbXApICU+JSBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfbm9fc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX25vX3plcm8pKSAlPiUgCiAgYmluZF9yb3dzKChmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZSwgImN1cnZlcyIpKSAlPiUgCiAgdW5uZXN0KHRlbXApICU+JSBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9ub19zeW1fY3JpdCkpKSAlPiUgCiAgYmluZF9yb3dzKChmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZSwgImN1cnZlcyIpKSAlPiUgCiAgdW5uZXN0KHRlbXApICU+JSBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9ub19zYW1lX25vX3plcm8pKSkgJT4lICAgCiAgYmluZF9yb3dzKChmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZSwgImN1cnZlcyIpKSAlPiUgCiAgdW5uZXN0KHRlbXApICU+JSBzZW1pX2pvaW4oYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX25vX3plcm8pKSkgJT4lIAogIGJpbmRfcm93cygoZml0X2FzeW1fYmVzdCAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICB0cmFuc211dGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGUsICJjdXJ2ZXMiKSkgJT4lIAogIHVubmVzdCh0ZW1wKSAlPiUgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV96ZXJvKSkpIAoKYXN5bV9wYXJfc192c19kIDwtIAogIChmaXRfYXN5bV9iZXN0ICU+JSAKICBncm91cF9ieShzdWJqZWN0LCB2ZXJ0aWNhbCkgJT4lIAogIHRyYW5zbXV0ZSh0ZW1wID0gbWFwKGZpdF9hc3ltX2Z1bGwsICJwYXIiKSkgJT4lIAogIHVubmVzdCh0ZW1wKSAlPiUgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX25vX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV9ub196ZXJvKSkgJT4lIAogIGJpbmRfcm93cygoZml0X2FzeW1fYmVzdCAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICB0cmFuc211dGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGUsICJwYXIiKSkgJT4lIAogIHVubmVzdCh0ZW1wKSAlPiUgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX3NhbWVfc2xvcGVfbm9fc3ltX2NyaXQpKSkgJT4lIAogIGJpbmRfcm93cygoZml0X2FzeW1fYmVzdCAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICB0cmFuc211dGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGUsICJwYXIiKSkgJT4lIAogIHVubmVzdCh0ZW1wKSAlPiUgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfbm9fc2FtZV9ub196ZXJvKSkpICU+JSAgIAogIGJpbmRfcm93cygoZml0X2FzeW1fYmVzdCAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCwgdmVydGljYWwpICU+JSAKICB0cmFuc211dGUodGVtcCA9IG1hcChmaXRfYXN5bV9mdWxsX3NhbWVfc2xvcGUsICJwYXIiKSkgJT4lIAogIHVubmVzdCh0ZW1wKSAlPiUgc2VtaV9qb2luKGJlc3RfYXN5bV9mdWxsX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV9ub196ZXJvKSkpICU+JSAKICBiaW5kX3Jvd3MoKGZpdF9hc3ltX2Jlc3QgJT4lIAogIGdyb3VwX2J5KHN1YmplY3QsIHZlcnRpY2FsKSAlPiUgCiAgdHJhbnNtdXRlKHRlbXAgPSBtYXAoZml0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlLCAicGFyIikpICU+JSAKICB1bm5lc3QodGVtcCkgJT4lIHNlbWlfam9pbihiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfemVybykpKSAKICAKYXN5bV9wYXJfc192c19kX2xvbmcgPC0gYXN5bV9wYXJfc192c19kICU+JSAKICBzcHJlYWQocGFybixwYXIpICU+JSAKICBtdXRhdGUocGZpcnN0ID0gcDEsIAogICAgICAgICBwc2Vjb25kID0gcDEgKyAuNSAqIChwNSAtIHA0KSwKICAgICAgICAgcHNlbnNvcnkgPSAuNSAqIChwZmlyc3QgKyBwc2Vjb25kKSwKICAgICAgICAgcGRlY2lzaW9uYWwgPSBwZmlyc3QgLSBwc2Vuc29yeSkKCmdncGxvdCgpICsgZmFjZXRfd3JhcChzdWJqZWN0IH4gdmVydGljYWwsIG5jb2wgPSA0KSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXN5bV9hdmVyYWdlc19zX3ZzX2QsIAogICAgICAgICAgICAgYWVzKHggPSBvcmllbnRhdGlvbiwgeSA9IHByb2IsIGNvbG9yID0gcmVmZXJlbmNlcykpICsKICBnZW9tX2xpbmUoZGF0YSA9IGFzeW1fY3VydmVzX3NfdnNfZCwgCiAgICAgICAgICAgIGFlcyh4ID0geCwgeSA9IHksIGNvbG9yID0gcmVmZXJlbmNlcykpICsKICAjIGdlb21fdmxpbmUoZGF0YSA9IGFzeW1fcGFyX3NfdnNfZF9sb25nLAogICMgICAgICAgICAgICBhZXMoeGludGVyY2VwdCA9IHBmaXJzdCwgbHR5ID0gInBmaXJzdCIpKSArCiAgIyBnZW9tX3ZsaW5lKGRhdGEgPSBhc3ltX3Bhcl9zX3ZzX2RfbG9uZywKICAjICAgICAgICAgICAgYWVzKHhpbnRlcmNlcHQgPSBwc2Vjb25kLCBsdHkgPSAicHNlY29uZCIpKSArCiAgICBnZW9tX3ZsaW5lKGRhdGEgPSBhc3ltX3Bhcl9zX3ZzX2RfbG9uZywKICAgICAgICAgICAgIGFlcyh4aW50ZXJjZXB0ID0gcHNlbnNvcnksIGx0eSA9ICJwc2Vuc29yeSIpKSArCiAgICBnZW9tX3ZsaW5lKGRhdGEgPSBhc3ltX3Bhcl9zX3ZzX2RfbG9uZywKICAgICAgICAgICAgIGFlcyh4aW50ZXJjZXB0ID0gcHNlbnNvcnkgKyBwZGVjaXNpb25hbCwgbHR5ID0gInBzZW5zb3J5ICArIHBkZWNpc2lvbmFsIikpICsKICB0aGVtZV9ncmV5KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgCiAKYGBgCgoKCiMjIyMgQWRkIGFsbCBiZXN0CmBgYHtyfQoKYmVzdF9hc3ltIDwtIGJlc3RfYXN5bV9mdWxsX25vX3NhbWVfc2xvcGVfc3ltX2NyaXRfc2FtZV9ub196ZXJvICU+JSAKICBiaW5kX3Jvd3MoYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9ub19zeW1fY3JpdCkgJT4lIAogIGJpbmRfcm93cyhiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X25vX3NhbWVfbm9femVybykgJT4lIAogIGJpbmRfcm93cyhiZXN0X2FzeW1fZnVsbF9zYW1lX3Nsb3BlX3N5bV9jcml0X3NhbWVfbm9femVybykgJT4lICAKICBiaW5kX3Jvd3MoYmVzdF9hc3ltX2Z1bGxfc2FtZV9zbG9wZV9zeW1fY3JpdF9zYW1lX3plcm8pIAoKCnJlZnMgPC0gZGF0X2FzeW0gJT4lIGRpc3RpbmN0KHZlcnRpY2FsLCByZWZlcmVuY2VzLCByZWZlcmVuY2UpCgphc3ltX2F2ZXJhZ2VzX3NfdnNfZF9iZXN0IDwtICBhc3ltX2F2ZXJhZ2VzX3NfdnNfZCAlPiUKICBsZWZ0X2pvaW4oYmVzdF9hc3ltKSAlPiUgCiAgbGVmdF9qb2luKHJlZnMpCiAgCmFzeW1fY3VydmVzX3NfdnNfZF9iZXN0IDwtIGFzeW1fY3VydmVzX3NfdnNfZCAlPiUgCiAgbGVmdF9qb2luKGJlc3RfYXN5bSkgJT4lIAogIGxlZnRfam9pbihyZWZzKQoKYXN5bV9wYXJfc192c19kX2Jlc3QgPC0gYXN5bV9wYXJfc192c19kICU+JSAKICBsZWZ0X2pvaW4oYmVzdF9hc3ltKSAKCmFzeW1fcGFyX3NfdnNfZF9iZXN0X2xvbmcgPC0gYXN5bV9wYXJfc192c19kX2xvbmcgJT4lIAogIGxlZnRfam9pbihiZXN0X2FzeW0pIAoKCmFzeW1fcGFyX3NfdnNfZF9iZXN0X2FicyA8LSBhc3ltX3Bhcl9zX3ZzX2RfYmVzdF9sb25nICU+JSAKICBzZWxlY3Qoc3ViamVjdCwgdmVydGljYWwsIHBzZW5zb3J5LCBwZGVjaXNpb25hbCwgYmVzdCkgJT4lIAogIGdhdGhlcihwYXJuLCBwYXIsIC0gc3ViamVjdCwgLSB2ZXJ0aWNhbCwgLWJlc3QpICU+JSAKICBtdXRhdGUocGFybiA9IGlmX2Vsc2UocGFybiA9PSAicHNlbnNvcnkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2Vuc29yeVxuYmlhcyIsICJEZWNpc2lvbmFsXG5iaWFzIiksCiAgICAgICAgICAgICAgICBhYnNfcGFyID0gYWJzKHBhcikpCmBgYAoKIyMjIFNhdmUgZGF0YQpgYGB7cn0Kc2F2ZShhc3ltX2F2ZXJhZ2VzX3NfdnNfZF9iZXN0LCBmaWxlID0gImxvZ2RhdGEvYXN5bV9hdmVyYWdlc19zX3ZzX2RfYmVzdC5SRGF0YSIpCnNhdmUoYXN5bV9jdXJ2ZXNfc192c19kX2Jlc3QsIGZpbGUgPSAibG9nZGF0YS9hc3ltX2N1cnZlc19zX3ZzX2RfYmVzdC5SRGF0YSIpCnNhdmUoYXN5bV9wYXJfc192c19kX2Jlc3QsIGZpbGUgPSAibG9nZGF0YS9hc3ltX3Bhcl9zX3ZzX2RfYmVzdC5SRGF0YSIpCnNhdmUoYXN5bV9wYXJfc192c19kX2Jlc3RfbG9uZywgZmlsZSA9ICJsb2dkYXRhL2FzeW1fcGFyX3NfdnNfZF9iZXN0X2xvbmcuUkRhdGEiKQpzYXZlKGFzeW1fcGFyX3NfdnNfZF9iZXN0X2FicywgZmlsZSA9ICJsb2dkYXRhL2FzeW1fcGFyX3NfdnNfZF9iZXN0X2Ficy5SRGF0YSIpCmBgYAoKCgoK